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.
The total size of the triangular array in moves can be calculated by the Triangular number:
Index
To calculate the index or offset of a PV into a one-dimensional move array by ply either requires storing incremental offsets
or variable multiplication from scratch:
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 [4] .
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.
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);}}
...
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[5] . Inside PVS, these arrays are not needed in the zero window search at all, and, 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.
Table of Contents
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.Therefor the triangular structure.
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| +-+Implementations
One-Dimensional Array
Size
The total size of the triangular array in moves can be calculated by the Triangular number:Index
To calculate the index or offset of a PV into a one-dimensional move array by ply either requires storing incremental offsetsor variable multiplication from scratch:
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 [4] .
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.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 [5] . Inside PVS, these arrays are not needed in the zero window search at all, and, 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 [6] , and explained by Harm Geert Muller [7] , 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.However, with a transposition table, aspiration, selectivity and that like, one cannot guarantee such stable behavior.
See also
Forum Posts
1998 ...
2000 ...
2005 ...
2010 ...
2015 ...
External Links
References
What links here?
Up one Level