Triangular+PV-Table

toc =Layout= Assuming a maximum search depth of N plies with pre-allocated stacks, the maximum possible PV-length decreases with increasing distance to root aka ply index during search, and actually needs one move less each ply deeper.
 * Home * Programming * Data * Triangular PV-Table**
 * [[image:triangular_table.JPG link="http://www.elementsbylizzie.com/Furn_Tables.html"]] ||~  || A **Triangular PV-Table** is an array of principal variations indexed by ply (distance to root). It is employed to collect the principal variation of best moves inside an alpha-beta or principal variation search - like the best score propagated up to the root. Inside an iterative deepening framework, it is most important to play the principal variation first during the next iteration. With some care in not overwriting PV-nodes, many programmers have abandoned PV-Table and reveal the PV from the transposition table  . ||
 * Triangular Table ||~  ||^   ||

> math maxLengthPV(ply) = N - ply math

Therefor the triangular structure. code ply maxLengthPV ++ 0  |N                                           | +--+-+ 1  |N-1                                       | ++-+ 2  |N-2                                     | +--+-+ 3  |N-3                                   | ++-+ 4  |N-4                                 | ...                       / N-4 |4      | +-+-+ N-3 |3   | +---+-+ N-2 |2 | +-+-+ N-1 |1| +-+ code

=Implementations=

Size
The total size of the triangular array in moves can be calculated by the [|Triangular number]:

> math size = 1+2+3+ \dotsb +(N-1)+N = {1/2}{N(N+1)} = {1/2}{(N^2+N)} = {N+1 \choose 2} math

Index
To calculate the index or offset of a PV into a one-dimensional move array by ply either requires storing incremental offsets > math index(0) = 0 math > math index(ply+1) = {index(ply) + N - ply} math

or variable multiplication from scratch:

> math index(ply) = {1/2} ply {(2N + 1 - ply )} math

This index calculation might as well be replaced by a redirection via a small pre-calculated lookup table with N entries of indices, pointers or references, similar to two-dimensional Java arrays as arrays of arrays with different size.

Pseudo Code
A didactic implementation of the Triangular PV-Table inside an Alpha-Beta routine. The routine //movcpy// copies up to //n// moves, but may terminate after copying a null move. To avoid the second condition, it is quite common to store the current length of the PV inside a PV structure. code format="cpp" MoveType pvArray[(N*N + N)/2];

void movcpy (MoveType* pTarget, const MoveType* pSource, int n) { while (n-- && (*pTarget++ = *pSource++)); }

int AlphaBeta(int alpha, int beta, int depth, int ply, int pvIndex) { ...  pvArray[pvIndex] = 0; // no pv yet pvNextIndex = pvIndex + N - ply; while ( move = getNextMove ) { make (move); score = -AlphaBeta(-beta, -alpha, depth-1, ply+1, pvNextIndex); unmake (move); ...     if (score > alpha) { alpha = score; pvArray[pvIndex] = move; movcpy (pvArray + pvIndex + 1, pvArray + pvNextIndex, N - ply - 1); }  }   ... code

Quadratic PV-Table
To avoid the above index calculation, many programmers roughly double the table space for an homogeneous two-dimensional array with all PVs of maximum size N. This allows cheaper indexing due the multiplication by the constant N only, possibly replaced by cheap instructions, i.e. shift for N == 128 (power of two). 

Linked List on the Stack
An option in C as well in Java is to reserve space for one PV on the stack as automatic variable inside the recursive search routine, and to pass a reference or pointer to the child nodes as demonstrated by Bruce Moreland. Inside PVS, these arrays are not needed in the zero window search at all, and, C|C99 conform [|variable-length arrays] on the stack are the way to "half" the required stacksize for linked "triangular" PV-arrays.

Pointer Array
Another alternative is an array of N pointers to global, homogeneous PV-arrays with size N each. Instead of copying moves alá memcpy, one may swap pointers. While this sounds promising at the first glance, the copy costs are negligible since PV-Nodes and raising alpha are quite rare.  =PV in PVS= As demonstrated by Daniel Shawul with TSCP, and explained by Harm Geert Muller , inside a perfectly stable NegaScout aka Principal Variation Search, a fail-high at a PV-node compared to a null window is always confirmed by the re-search with an exact score improving alpha and will either become part of a new PV at the root or overwritten by a further improvement. Thus, under such conditions, there is no need to keep an array of principal variations, but only one.

code format="cpp" MoveType pvArray[N]; code

However, with a transposition table, aspiration, selectivity and that like, one cannot guarantee such stable behavior.

=See also=
 * Best Move
 * Hash Move
 * Killer Move
 * Principal variation
 * PV-Move
 * Refutation Table

=Forum Posts=

1998 ...

 * [|Storing the PV in a search routine] by Scott Gasch, CCC, June 09, 1998

2000 ...

 * [|PV array] by Nagendra Singh Tomar, CCC, October 10, 2002
 * [|triangular pv vs. hash move pv] by Stuart Cracraft, CCC, September 11, 2004
 * [|Instability thing...] by Sune Fischer, CCC, September 18, 2004

2005 ...

 * [|Extracting PV from TT] by Colin, CCC, September 12, 2009

2010 ...

 * [|Taken from CCC (Stockfish & mainlines)] by Rebel, OpenChess Programming Forum, July 12, 2010
 * [|Full Principal Variation Retrieval] by Hieu Nguyen, CCC, September 06, 2010
 * [|restartable nodes and the tri-angular array] by Harm Geert Muller, CCC, July 11, 2012
 * [|triangular pv] by Daniel Shawul, CCC, March 22, 2013

2015 ...

 * [|Collecting Principal variation] by Syed Fahad, CCC, March 29, 2015
 * [|Collecting PVs of Qsearch ?] by Mahmoud Uthman, CCC, October 22, 2016 » Principal Variation, Quiescence Search
 * [|capturing PV in QSearch] by thevinenator, OpenChess Forum, January 20, 2017
 * [|Collecting PV in a PVS search ?] by Mahmoud Uthman, CCC, June 11, 2017 » Principal Variation

=External Links=
 * [|Collecting the Principal Variation] from Bruce Moreland's [|Programming Topics]

=References= =What links here?= include page="Triangular PV-Table" component="backlinks" limit="80"
 * Up one Level**