Hello,
I have finally traced the bug in my program that caused it to not able to mate endings of KQK and KRK when a position is replayed without the transposition table cleared. The content of the table stored mate scores that were incorrect.
First about aspiration windows for root search. The usual practice is to set [alpha, beta] to cover the expected best score of every iteration, say about 100cp about the expected value. But if an iteration returns a winning +mate score, the iteration may be reset to seek the shortest mate, iterating through even depth 2/4/6/8 until the best possible mate is reached when root search returns. For this, the setting may be:
alpha = bestscore = winning_mate_score.
beta = INFI;
There is a corresponding best move.
This is perfectly safe and probably the correct way. My program earlier found that it had to set alpha = -INFI and the reason was due to a bug elsewhere.
The bug was in the way I hashed mate scores. It had nothing to do with the +/- ply adjustment needed to the scores for hashing. It was done accordingly. The bug was in the bound type hashed - exact, upper or lower.
I don't know how other program hash mate scores. The way in my program was all the while :
storehash(score, MAX_DEPTH, EX/UB/LB, bestmove, ...);
It was always with max depth.
For non-mate scores, the bound type of the score to hash changes with the search depth. With max depth for mate scores, the way to determine bound type to hash would be different. 'exact' for +mate means the best possible mate; eg. INF - 1 is always 'exact'. In the hashing of interior nodes, there are some subtleties if root search is seeking a better mate. Some +mate and -mate scores may not be hashed as the bound type is indeterminate corresponding to MAX_DEPTH. It is clearer that I show the hashing code at the end of my pvs search with comments. Only the mate scores are of interest to this topic:
Code: Select all
HASH_AND_RETURN:
;
/* M_MATE is minus-mate, P_MATE is plus-mate. */
if (bestmove) {
CUT:
if (best > M_MATE) {
if (best < P_MATE) {
if (best ^ 0) {
if (depth <= 0) {
/* QS */
storehash(best, incheck || (genChecks && best > alpha0) ? 1 : 0,
best <= alpha0 ? UB : (best >= beta || genChecks ? LB : EX),
bestmove, currstack->xeval);
} else {
storehash(best, depth, best <= alpha0 ? UB : (best >= beta ? LB : EX),
bestmove, currstack->xeval);
}
}
} else {
/* winning mate scores */
assert(ply & 1 ? !(best & 1) : best & 1);
if (best == INFI - ply - 1) {
/* mate-in-1 */
storehash(best + ply, MAX_DEPTH, EX, bestmove, -INFI);
} else if (best > alpha0) {
storehash(best + ply, MAX_DEPTH, LB, bestmove, -INFI);
}
/* otherwise indeterminate bound type */
}
} else {
/* losing mate score */
assert(ply & 1 ? (best & 1) : !(best & 1));
if (best == -INFI + ply + 2) {
/* this is an exact score !!! */
storehash(best - ply, MAX_DEPTH, EX, bestmove, -INFI);
} else if (best <= alpha0) {
storehash(best - ply, MAX_DEPTH, UB, bestmove, -INFI);
}
/* otherwise indeterminate bound type */
}
return best;
} else {
if (incheck) {
/* losing mate, exact */
storehash(-INFI, MAX_DEPTH, EX, 0, -INFI);
return -INFI + ply;
}
if (depth > 0) {
/* stalemate*/
storehash(1, MAX_DEPTH, EX, 0, -INFI);
return 1;
}
/* QS - without a bestmove ==> best is eval; hash EX only if best == xeval.
*/
assert(best ^ -INFI);
if (best ^ 0 && best == currstack->xeval) {
storehash(best, 0, EX, 0, currstack->xeval);
}
return best;
}
Best Regards,
Rasjid.