Looking code of a few engines, even top ones like Crafty, it looks to me that all have a draw-score bug:
Let's suppose a branch that in the frontier node, before call quiesce, it is a calm position. When enter quiesce first time, evaluation is called and make a decision (i.e. the score > beta, so return beta).... but, what about if the last move is a 3-repetition or a 50-mov rule draw. It is not examined and it is returned a eval score and not a draw one.
Of course, in the following iteration this could solved, but new nodes will have the same problem.
Does this is a problem? is it important? or am I who is seeing ghots?
Regards,
Are everybody making this bad?
Moderators: hgm, Rebel, chrisw
-
- Posts: 620
- Joined: Fri Feb 08, 2008 10:44 am
- Location: Madrid - Spain
-
- Posts: 1922
- Joined: Thu Mar 09, 2006 12:51 am
- Location: Earth
Re: Are everybody making this bad?
It's interesting, it looks like Crafty has that bug. Bob might have reasons for not doing it, it might not be worth the overhead according to massive cluster testing. I know one certain engine that doesn't have the bug though...
Code: Select all
/**
The quiescence search.
**/
case QSEARCH_START:
#ifdef SMP
smp_block[board.id].q_nodes++;
#else
zct->q_nodes++;
#endif
if (sb->ply >= zct->max_depth_reached)
zct->max_depth_reached = sb->ply;
if (sb->ply >= MAX_PLY - 1)
RETURN(evaluate(&sb->eval_block));
if (board.fifty_count >= 100 && !is_mate())
RETURN(DRAW);
if (is_repetition(sb->ply > 1 ? 2 : 3))
RETURN(DRAW);
/* mate-distance pruning */
sb->alpha = MAX(sb->alpha, -MATE + sb->ply);
sb->beta = MIN(sb->beta, MATE - sb->ply - 1);
if (sb->alpha >= sb->beta)
RETURN(sb->alpha);
/* material draw pruning */
if (!can_mate(board.side_tm))
{
sb->beta = MIN(sb->beta, DRAW);
if (sb->alpha >= sb->beta)
RETURN(sb->alpha);
}
if (!can_mate(board.side_ntm))
{
sb->alpha = MAX(sb->alpha, DRAW);
if (sb->alpha >= sb->beta)
RETURN(sb->alpha);
}
/* Probe the hash table. */
if (hash_probe(sb, TRUE))
RETURN(sb->alpha);
#ifdef EGBB
/* Probe the bitbases. */
if (egbb_is_loaded && pop_count(board.occupied_bb) <= 5)
{
if (probe_bitbases(&r) && r != _NOTFOUND)
{
/* draw, exact score */
if (r == 0)
sb->alpha = sb->beta = 0;
/* mate */
else if (r > 0)
sb->alpha = MAX(MATE - MAX_PLY - 1, sb->alpha);
else if (r < 0)
sb->beta = MIN(-(MATE - MAX_PLY - 1), sb->beta);
if (sb->alpha >= sb->beta)
{
hash_store(sb, NO_MOVE, r, HASH_LOWER_BOUND, FALSE);
hash_store(sb, NO_MOVE, r, HASH_LOWER_BOUND, TRUE);
RETURN(r);
}
}
}
#endif
sb->check = check_squares();
/* If we are in check and depth is sufficient, try all evasions. */
if (sb->check && sb->depth > 0)
{
sb->threat = TRUE;
sb->select_state = SELECT_HASH_MOVE;
}
/* Normal quiescence stand pat score, plus move generation. */
else
{
/* Evaluate for the stand pat. */
r = sb->best_score = evaluate(&sb->eval_block);
if (r > sb->alpha)
{
sb->alpha = r;
if (r >= sb->beta)
{
/* Is this worth it? */
hash_store(sb, NO_MOVE, r, HASH_LOWER_BOUND, TRUE);
RETURN(r);
}
}
sb->select_state = SELECT_GEN_CAPS;
}
-
- Posts: 27811
- Joined: Fri Mar 10, 2006 10:06 am
- Location: Amsterdam
- Full name: H G Muller
Re: Are everybody making this bad?
Joker also would recognize the position as a repetition, and therefore might not make the move. Micro-Max would recognize a repetition after making the move if it was a repetition of a position that had occurred in the game.
Last edited by hgm on Wed Nov 26, 2008 7:02 pm, edited 2 times in total.
Re: Are everybody making this bad?
Maybe some engines already assign a draw score after the second repetition. This would avoid the bug, wouldn't it?
-
- Posts: 20943
- Joined: Mon Feb 27, 2006 7:30 pm
- Location: Birmingham, AL
Re: Are everybody making this bad?
I am not sure it is a "bug". Once a piece is captured, repetition is not possible, nor is 50-move rule draw. I tried it in the q-search check/check evasion, but it hurt on cluster testing, probably because of the nps drop this produces since it is done in the biggest part of the tree. Ditto for storing and probing hash table. I have it on my list to test again, but several years ago I ran a lot of tests and concluded that the 10% slowdown, which shrunk the tree by 10% was essentially a "wash". Not hashing in qsearch has a big advantage, however, in that there are more nodes out there than in the regular search, so you don't replace nearly as often since less than 50% of total nodes searched get stored. I know of one commercial program (very strong as well) that claims to not even do a q-search at all, just applies SEE to the tips.Zach Wegner wrote:It's interesting, it looks like Crafty has that bug. Bob might have reasons for not doing it, it might not be worth the overhead according to massive cluster testing. I know one certain engine that doesn't have the bug though...
Code: Select all
/** The quiescence search. **/ case QSEARCH_START: #ifdef SMP smp_block[board.id].q_nodes++; #else zct->q_nodes++; #endif if (sb->ply >= zct->max_depth_reached) zct->max_depth_reached = sb->ply; if (sb->ply >= MAX_PLY - 1) RETURN(evaluate(&sb->eval_block)); if (board.fifty_count >= 100 && !is_mate()) RETURN(DRAW); if (is_repetition(sb->ply > 1 ? 2 : 3)) RETURN(DRAW); /* mate-distance pruning */ sb->alpha = MAX(sb->alpha, -MATE + sb->ply); sb->beta = MIN(sb->beta, MATE - sb->ply - 1); if (sb->alpha >= sb->beta) RETURN(sb->alpha); /* material draw pruning */ if (!can_mate(board.side_tm)) { sb->beta = MIN(sb->beta, DRAW); if (sb->alpha >= sb->beta) RETURN(sb->alpha); } if (!can_mate(board.side_ntm)) { sb->alpha = MAX(sb->alpha, DRAW); if (sb->alpha >= sb->beta) RETURN(sb->alpha); } /* Probe the hash table. */ if (hash_probe(sb, TRUE)) RETURN(sb->alpha); #ifdef EGBB /* Probe the bitbases. */ if (egbb_is_loaded && pop_count(board.occupied_bb) <= 5) { if (probe_bitbases(&r) && r != _NOTFOUND) { /* draw, exact score */ if (r == 0) sb->alpha = sb->beta = 0; /* mate */ else if (r > 0) sb->alpha = MAX(MATE - MAX_PLY - 1, sb->alpha); else if (r < 0) sb->beta = MIN(-(MATE - MAX_PLY - 1), sb->beta); if (sb->alpha >= sb->beta) { hash_store(sb, NO_MOVE, r, HASH_LOWER_BOUND, FALSE); hash_store(sb, NO_MOVE, r, HASH_LOWER_BOUND, TRUE); RETURN(r); } } } #endif sb->check = check_squares(); /* If we are in check and depth is sufficient, try all evasions. */ if (sb->check && sb->depth > 0) { sb->threat = TRUE; sb->select_state = SELECT_HASH_MOVE; } /* Normal quiescence stand pat score, plus move generation. */ else { /* Evaluate for the stand pat. */ r = sb->best_score = evaluate(&sb->eval_block); if (r > sb->alpha) { sb->alpha = r; if (r >= sb->beta) { /* Is this worth it? */ hash_store(sb, NO_MOVE, r, HASH_LOWER_BOUND, TRUE); RETURN(r); } } sb->select_state = SELECT_GEN_CAPS; }
-
- Posts: 20943
- Joined: Mon Feb 27, 2006 7:30 pm
- Location: Birmingham, AL
Re: Are everybody making this bad?
I don't think it matters as you would not see the second repetition in the q-search. I count the 2nd as a draw, of course... To do otherwise invites overlooked repetitions and draws in otherwise won positions.Guetti wrote:Maybe some engines already assign a draw score after the second repetition. This would avoid the bug, wouldn't it?
-
- Posts: 27811
- Joined: Fri Mar 10, 2006 10:06 am
- Location: Amsterdam
- Full name: H G Muller
Re: Are everybody making this bad?
I started out using SEE-based termination in micro-Max as well, (i.e., only considering capturing the last-moving piece in QS), but changing to an all-capture QS produced a 120 Elo strength increase, and thus was well worth the number of characters spent to program it. Even despite the fact that there was no real move ordering, except that the MVV/LVA capture was tried first. (And all other captures in move-gen order.)bob wrote:I know of one commercial program (very strong as well) that claims to not even do a q-search at all, just applies SEE to the tips.
Micro-Max does never do any move sorting other than trying the best move of the previous IID iteration (possibly communicated through the hash table) first. But due to IID this still results in a reasonable move ordering: a QS iteration preceeds a d=1 iterations, so all captures are searched before any non-captures.
-
- Posts: 20943
- Joined: Mon Feb 27, 2006 7:30 pm
- Location: Birmingham, AL
Re: Are everybody making this bad?
I used the SEE trick myself somewhere around 1975. But when I went to full-width and added q-search, the program played better. Amir once discussed this here and said Junior (a) has no q-search at all and (b) doesn't hash in the last 1 or 2 plies (memory fails me on whether it was 1 or 2 however). I'm not sure if he ever mentioned how he used SEE(), as you could just use it to verify the safety of the moves leading to leaf positions, or you could use it on any apparently hung piece which might be better although I have not tried it.hgm wrote:I started out using SEE-based termination in micro-Max as well, (i.e., only considering capturing the last-moving piece in QS), but changing to an all-capture QS produced a 120 Elo strength increase, and thus was well worth the number of characters spent to program it. Even despite the fact that there was no real move ordering, except that the MVV/LVA capture was tried first. (And all other captures in move-gen order.)bob wrote:I know of one commercial program (very strong as well) that claims to not even do a q-search at all, just applies SEE to the tips.
Micro-Max does never do any move sorting other than trying the best move of the previous IID iteration (possibly communicated through the hash table) first. But due to IID this still results in a reasonable move ordering: a QS iteration preceeds a d=1 iterations, so all captures are searched before any non-captures.
-
- Posts: 1922
- Joined: Thu Mar 09, 2006 12:51 am
- Location: Earth
Re: Are everybody making this bad?
It is true that repetitions and 50-move draws can't happen after captures. But, without testing, I'd imagine that it would help to run the test if you do checks in the qsearch to avoid certain perpetuals.bob wrote:I am not sure it is a "bug". Once a piece is captured, repetition is not possible, nor is 50-move rule draw. I tried it in the q-search check/check evasion, but it hurt on cluster testing, probably because of the nps drop this produces since it is done in the biggest part of the tree. Ditto for storing and probing hash table. I have it on my list to test again, but several years ago I ran a lot of tests and concluded that the 10% slowdown, which shrunk the tree by 10% was essentially a "wash". Not hashing in qsearch has a big advantage, however, in that there are more nodes out there than in the regular search, so you don't replace nearly as often since less than 50% of total nodes searched get stored. I know of one commercial program (very strong as well) that claims to not even do a q-search at all, just applies SEE to the tips.
-
- Posts: 20943
- Joined: Mon Feb 27, 2006 7:30 pm
- Location: Birmingham, AL
Re: Are everybody making this bad?
I already do this, but only in the qchecks and qevasions modules, not anywhere else. So Crafty will _always_ see the repetition or 50-move draw mentioned at the start of this thread, since the first level of q-search is always the QuiesceChecks() function that checks for reps/etc at the front, and for any check this module produces, QuiseceEvasions() is called and it also checks for repetitions/50-move draws, although I do not hash in those functions...Zach Wegner wrote:It is true that repetitions and 50-move draws can't happen after captures. But, without testing, I'd imagine that it would help to run the test if you do checks in the qsearch to avoid certain perpetuals.bob wrote:I am not sure it is a "bug". Once a piece is captured, repetition is not possible, nor is 50-move rule draw. I tried it in the q-search check/check evasion, but it hurt on cluster testing, probably because of the nps drop this produces since it is done in the biggest part of the tree. Ditto for storing and probing hash table. I have it on my list to test again, but several years ago I ran a lot of tests and concluded that the 10% slowdown, which shrunk the tree by 10% was essentially a "wash". Not hashing in qsearch has a big advantage, however, in that there are more nodes out there than in the regular search, so you don't replace nearly as often since less than 50% of total nodes searched get stored. I know of one commercial program (very strong as well) that claims to not even do a q-search at all, just applies SEE to the tips.