Principal+Variation+Search

an enhancement to Alpha-Beta, based on null- or zero window searches of none PV-nodes, to prove a move is worse or not than an already safe score from the principal variation. || toc =The Idea= In most of the nodes we need just a bound, proving that a move is unacceptable for us or for the opponent, and not the exact score. This is needed only in so-called principal variation - a sequence of moves acceptable for both players (i.e. not causing a beta-cutoff anywhere in the path) which is expected to propagate down to the root. If a lower-depth search has already established such a sequence, finding a series of moves whose value is greater than alpha but lower than beta throughout the entire branch, the chances are that deviating from it will do us no good. So in a PV-node only the first move (the one which is deemed best by the previous iteration of an iterative deepening framework) is searched in the full window in order to establish the expected node value.
 * Home * Search * Principal Variation Search**
 * [[image:Cage-variations-iii-14-small.jpg link="https://en.wikipedia.org/wiki/File:Cage-variations-iii-14-small.jpg"]] ||~ || **Principal Variation Search (PVS)**,
 * John Cage - Variations III, No. 14 ||~ ||^ ||

When we already have a PV-move (defined as the move that raised alpha in a PV-node) we assume we are going to stick with it. To confirm our belief, a null- or zero window search centered around alpha is conducted to test if a new move can be better. If so, with respect to the null window but not with respect to the full window, we have to do a re-search with the full normal window. Since null window searches are cheaper, with a good move ordering we expect to save about 10% of a search effort.

Bruce Moreland's PVS implementation waits until a move is found that improves alpha, and then searches every move after that with a zero window around alpha. The alpha improvement usually occurs at the first move, and always at the leftmost nodes (assuming from left to right traversal) with a most open alpha-beta window of +-oo. In re-searches or with aspiration-windows the first moves may rarely not improve alpha. As pointed out by Edmund Moshammer, Gian-Carlo Pascutto, Robert Hyatt and Vincent Diepeveen, it is recommend to only search the first move with an open window, and then every other move after that with a zero window. A further improvement (similar to that known from the NegaScout algorithm) is possible. Since there is not much to be gained in the last two plies of the normal search, one might disable PVS there, but programs respond differently to that change.  =History= PVS was introduced by Tony Marsland and Murray Campbell in 1982 as nomination of Finkel's and Fishburn's routine **Palphabeta**, in Fishburn's 1981 thesis called **Calphabeta**, which in turn is similar to Judea Pearl's Scout  :

Despite the publications, PVS was already used in 1978, as mentioned by Robert Hyatt :

John Philip Fishburn in a note, September 2010:

and subsequently some details about Belle's PVS-implementation ...

=PVS and NegaScout= Most PVS implementations are similar to Reinefeld's NegaScout, and are used by most todays chess programs. It is based on the accuracy of the move ordering. Typically, modern chess programs find fail-highs on the first move around 90% of the time. This observation can be used to narrow the window on searches of moves after the first, because there is a high probability that they will be lower than the score of the first move.

Reinefeld's original implementation introduces one additional variable on the stack (only b, since after a = alpha, alpha is not needed any longer), for a slightly simpler control structure than PVS. It has therefor set a new null window at the end of the loop ( b = a + 1 ), but has to consider the move count for the re-search condition though. His implementation trusts the null-window score, even if the re-search doesn't confirm the alpha increase, eventually due to search instability. While re-searching, it uses the narrow window of {score, beta}, while other implementations dealing with search instability, re-search with {alpha, beta}. Practically, due to Quiescence Search, and fail-soft implementations of PVS, the two algorithms are essentially equivalent to each other - they expand the same search tree.

Guido Schimmels
Guido Schimmels in a CCC post on the difference of PVS vs. NegaScout : code format="cpp" value = PVS(-(alpha+1),-alpha) if(value > alpha && value < beta) { value = PVS(-beta,-alpha); } code code format="cpp" value = NegaScout(-(alpha+1),-alpha) if(value > alpha && value < beta && depth > 1) { value2 = NegaScout(-beta,-value) value = max(value,value2); } code
 * PVS**:
 * PVS**:
 * NegaScout**:

Yngvi Björnsson
Quote by Yngvi Björnsson from CCC, January 05, 2000 :

||

Dennis Breuker
Quote by Dennis Breuker from CCC, July 28, 2004 :
 * Q:



=Pseudo Code= This demonstrates PVS in a fail-hard framework, where alpha and beta are hard bounds of the returned score. code format="cpp" int pvSearch( int alpha, int beta, int depth ) { if( depth == 0 ) return quiesce( alpha, beta ); bool bSearchPv = true; for ( all moves) { make if ( bSearchPv ) { score = -pvSearch(-beta, -alpha, depth - 1); } else { score = -pvSearch(-alpha-1, -alpha, depth - 1); if ( score > alpha ) // in fail-soft ... && score < beta ) is common           score = -pvSearch(-beta, -alpha, depth - 1); // re-search      }      unmake      if( score >= beta )         return beta;   // fail-hard beta-cutoff      if( score > alpha ) {         alpha = score; // alpha acts like max in MiniMax         bSearchPv = false;  // *1) }  }   return alpha; // fail-hard } code 1) it is recommend to set bSearchPv outside the score > alpha condition.

 =PVS + ZWS= Often, programmers split PVS inside a pure PV-node search and a separate and a more compact scout search with null windows. code format="cpp" int pvSearch( int alpha, int beta, int depth ) { if( depth == 0 ) return quiesce(alpha, beta); bool bSearchPv = true; for ( all moves) { make if ( bSearchPv ) { score = -pvSearch(-beta, -alpha, depth - 1); } else { score = -zwSearch(-alpha, depth - 1); if ( score > alpha ) // in fail-soft ... && score < beta ) is common           score = -pvSearch(-beta, -alpha, depth - 1); // re-search      }      unmake      if( score >= beta )         return beta;   // fail-hard beta-cutoff      if( score > alpha ) {         alpha = score; // alpha acts like max in MiniMax         bSearchPv = false;   // *1) }  }   return alpha; }

// fail-hard zero window search, returns either beta-1 or beta int zwSearch(int beta, int depth ) { // alpha == beta - 1 // this is either a cut- or all-node if( depth == 0 ) return quiesce(beta-1, beta); for ( all moves) { make score = -zwSearch(1-beta, depth - 1); unmake if( score >= beta ) return beta;  // fail-hard beta-cutoff }  return beta-1; // fail-hard, return alpha } code 1) it is recommend to set bSearchPv outside the score > alpha condition.

 =PVS and Aspiration= When implementing PVS together with the aspiration window, one must be aware that in this case also a normal window search might fail, leaving the program with no move and no PV. (Actually this is the reason why I wrote "When we already have a PV move" and not "searching later moves").
 * PVS and aspiration

A state of the art fail-soft PVS implementation, called without aspiration, was posted by Vincent Diepeveen inside the mentioned CCC thread : code format="cpp" Call from root: rootscore = PVS(-infinite, infinite, depthleft);

int PVS(alfa,beta,depthleft) { if( depthleft <= 0 ) return qsearch(alfa, beta);

// using fail soft with negamax: make first move bestscore = -PVS(-beta, -alfa, depthleft-1); unmake first move if( bestscore > alfa ) { if( bestscore >= beta ) return bestscore; alfa = bestscore; }

for( all remaining moves ) { make move score = -PVS(-alfa-1, -alfa, depthleft-1); // alphaBeta or zwSearch if( score > alfa && score < beta ) { // research with window [alfa;beta] score = -PVS(-beta, -alfa, depthleft-1); if( score > alfa ) alfa = score; }     unmake move if( score > bestscore ) { if( score >= beta ) return score; bestscore = score; }  }   return bestscore; } code

=See also=
 * Alpha-Beta
 * CPW-Engine_search
 * Enhanced Forward Pruning
 * Iterative Deepening
 * Move Ordering
 * MTD(f)
 * NegaScout
 * Null Window
 * PVS and aspiration
 * Scout

=Publications=

1980 ...

 * Judea Pearl (**1980**). //Asymptotic Properties of Minimax Trees and Game-Searching Procedures.// [|Artificial Intelligence], Vol. 14, No. 2
 * Judea Pearl (**1980**). //Scout: A Simple Game-Searching Algorithm with Proven Optimal Properties//. Proceedings of the First Annual National Conference on Artificial Intelligence. Stanford. [|pdf]
 * Raphael Finkel, John Philip Fishburn (**1980**). //Parallel Alpha-Beta Search on Arachne.// IEEE International Conference on Parallel Processing
 * John Philip Fishburn (**1980**). //An optimization of alpha-beta search//. SIGART Bulletin, Issue 72
 * John Philip Fishburn (**1981**). //Analysis of Speedup in Distributed Algorithms//. Ph.D. Thesis, [|University of Wisconsin-Madison], [|pdf], //Calphabeta// at page 167
 * Tony Marsland, Murray Campbell (**1982**). //Parallel Search of Strongly Ordered Game Trees.// ACM Computing Surveys, Vol. 14, No. 4, [|pdf]
 * Murray Campbell, Tony Marsland (**1983**). //A Comparison of Minimax Tree Search Algorithms//. [|Artificial Intelligence], Vol. 20, No. 4, pp. 347-367. ISSN 0004-3702.
 * Tony Marsland (**1983**). //Relative Efficiency of Alpha-beta Implementations//. Procs. 8th Int. Joint Conf. on Art. Intell., pp. 763-766. Kaufman, Los Altos, [|pdf]
 * Alexander Reinefeld (**1983**). //An Improvement to the Scout Tree-Search Algorithm.// ICCA Journal, Vol. 6, No. 4, [|pdf]

1985 ...

 * Agata Muszycka-Jones, Rajjan Shinghal (**1985**). //An empirical comparison of pruning strategies in game trees//. IEEE Transactions on Systems, Man, and Cybernetics, Vol. 15, No. 3
 * Tony Marsland (**1986**). //A Review of Game-Tree Pruning.// ICCA Journal, Vol. 9, No. 1, [|pdf]
 * Alexander Reinefeld, Tony Marsland (**1987**). //A Quantitative Analysis of Minimal Window Search.// [|IJCAI-87], [|pdf]

2000 ...

 * Mark Winands, Jaap van den Herik, Jos Uiterwijk and Erik van der Werf (**2003**). //Enhanced forward pruning.// Accepted for publication. [|pdf] (with PVS modifications)

=Forum Posts=

1995 ...

 * [|Trick Marsland] by Robert Hyatt, rgcc, February 15, 1996
 * [|Re: Zero-width Window Null Move Search] by Guido Schimmels, CCC, June 18, 1998 » NegaScout
 * [|Fail-soft with PVS?] by Will Singleton, CCC, March 09, 1999 » Fail-Soft
 * [|Re: negascout vs pvs] by Dave Gomboc, CCC, June 04, 1999

2000 ...
> [|Re: Fruit - Question for Fabien] by Fabien Letouzey, CCC, March 11, 2004
 * [|PVS and NegaScout] by Gian-Carlo Pascutto, CCC, January 05, 2000
 * [|A Question on simple Alpha-Beta versus PVS/Negascout] by Andrei Fortuna, CCC, March 21, 2000 » Alpha-Beta, NegaScout
 * [|What is Negascout and why is MWS PVS?] by Severi Salminen, CCC, November 24, 2000
 * [|Please explain the difference between PVS and NegaScout] by Severi Salminen, CCC, March 02, 2001
 * [|QSearch as PVS ?] by Matthias Gemuh, CCC, January 14, 2004
 * [|Fruit - Question for Fabien] by Dan Honeycutt, CCC, March 11, 2004 » Fruit, Node Types, Transposition Table, Principal variation
 * [|Q. Aspiration, PVS, Fail-Soft] by David B. Weller, CCC, July 02, 2004
 * [|negascout and PVS?] by Peter Alloysius, CCC, July 26, 2004 » NegaScout

2005 ...

 * [|Slight enhancement to PVS] by Pradu Kannan, Winboard Programming Forum, June 10, 2007
 * [|Search questions] by Sven Schüle, Winboard Forum, July 17, 2007 » Fail Soft
 * [|when to try zero window search], CCC, November 14, 2008
 * [|PVS] by Edmund Moshammer, CCC, March 12, 2009
 * [|Re: PVS] by Robert Hyatt, CCC, March 12, 2009
 * [|Re: PVS] by Vincent Diepeveen, CCC, March 14, 2009
 * [|No PVS at low depths?] by Mark Lefler, CCC, June 05, 2009
 * [|A way to improve PVS] by Sergei S. Markoff, CCC, September 07, 2009

2010 ...

 * [|The strengths and weaknesses of PVS] by Edmund Moshammer, CCC, June 18, 2010
 * [|Memory-PV-Search] by Onno Garms, CCC, March 13, 2011 » Onno
 * [|PV Search and Transposition Table] by Cheney Nattress, CCC, December 20, 2012
 * [|principle variation search] by nak3c, OpenChess Forum, January 09, 2013
 * [|Implementing pvs] by CDaley11, OpenChess Forum, January 13, 2013
 * [|Improvement from PVS] by Matthew Lai, CCC, September 09, 2014
 * [|Your experience with PVS + Aspiration window] by Fabio Gobbato, CCC, October 07, 2014 » Aspiration Windows, PVS and aspiration

2015 ...

 * [|Question on standard implementation of PVS+NWS] by Rob Williamson, CCC, March 19, 2015
 * [|PVS/NegaScout: Actual benefits] by Vincent Tang, CCC, July 06, 2016
 * [|bound type in PVS ?] by Mahmoud Uthman, CCC, January 23, 2017 » Bound, Exact Score
 * [|LMR and PVS] by thevinenator, OpenChess Forum, February 10, 2017 » Late Move Reductions
 * [|PVS & Embla] by Folkert van Heusden, CCC, October 19, 2017 » Embla

=External Links=
 * [|Principal Variation Search] from Bruce Moreland's [|Programming Topics]
 * [|NegaScout or Principal Variation Search from Wikipedia]

=Video Tutorial= > media type="custom" key="26008670"
 * A summary description of PVS and how it works by Jonathan Warkentin, [|YouTube] Video

=References= =What links here?= include page="Principal Variation Search" component="backlinks" limit="320"
 * Up one level**