The code in stockfish means that the problem that Bob described does not happen but you did not mention it so I thought maybe I do not understand the code.
Uri
Stockfish-1.5 Detects mate then changes mind?
Moderator: Ras
-
- Posts: 10874
- Joined: Thu Mar 09, 2006 12:37 am
- Location: Tel-Aviv Israel
-
- Posts: 2684
- Joined: Sat Jun 14, 2008 9:17 pm
Re: Stockfish-1.5 Detects mate then changes mind?
There is something more in root_search(), I repost the code with the missing piece.
Code: Select all
root_search(alpha, beta)
{
for (int i = 0; i < RootMoveCount && alpha < beta; i++)
{
if (alpha >= beta)
{
// We failed high, invalidate and skip next moves, leave node-counters
// and beta-counters as they are and quickly return, we will try to do
// a research at the next iteration with a bigger aspiration window.
rml.set_move_score(i, -VALUE_INFINITE);
continue;
}
if (i == 0)
value = -search_pv(-beta, -alpha)
else
{
value = -search(-alpha-1,-alpha)
if (value > alpha)
value = -search_pv(-beta,-alpha)
}
if (i == 0 || value > alpha)
best_i = i
if (value > alpha)
alpha = value
}
return alpha;
}
-
- Posts: 613
- Joined: Sun Jan 18, 2009 7:03 am
Re: Stockfish-1.5 Detects mate then changes mind?
Marco,
please note that I wrote everything in short form. There is an extra
"alpha < beta" condition compared to Stockfish code.
please note that I wrote everything in short form. There is an extra
"alpha < beta" condition compared to Stockfish code.
Code: Select all
for (int i = 0; i < RootMoveCount && alpha < beta; i++)
Joona Kiiski
-
- Posts: 4052
- Joined: Thu May 15, 2008 9:57 pm
- Location: Berlin, Germany
- Full name: Sven Schüle
Re: Stockfish-1.5 Detects mate then changes mind?
I don't believe this is close to the real code since the "if (alpha >= beta)" condition would never be true due to the loop condition.mcostalba wrote:There is something more in root_search(), I repost the code with the missing piece.
Code: Select all
root_search(alpha, beta) { for (int i = 0; i < RootMoveCount && alpha < beta; i++) { if (alpha >= beta) { // Note that this condition is always false !!! } // ... }
Sven
-
- Posts: 4052
- Joined: Thu May 15, 2008 9:57 pm
- Location: Berlin, Germany
- Full name: Sven Schüle
Re: Stockfish-1.5 Detects mate then changes mind?
Actually the current Stockfish 1.5 source code from the JA site looks a bit different, more like this, so that it makes more sense:Sven Schüle wrote:I don't believe this is close to the real code since the "if (alpha >= beta)" condition would never be true due to the loop condition.
Code: Select all
root_search(alpha, beta)
{
for (int i = 0; i < RootMoveCount && !AbortSearch; i++)
{
if (alpha >= beta)
{
// We failed high ...
}
// ...
}
-
- Posts: 4052
- Joined: Thu May 15, 2008 9:57 pm
- Location: Berlin, Germany
- Full name: Sven Schüle
Re: Stockfish-1.5 Detects mate then changes mind?
Within this piece of code, which is from the currently published Stockfish 1.5 source, I wonder what the real intention is: either "quickly return", as stated in the comment, or "continue" (with the remaining moves). Only one of both can be meant, but which one?mcostalba wrote:Code: Select all
if (alpha >= beta) { // We failed high, invalidate and skip next moves, leave node-counters // and beta-counters as they are and quickly return, we will try to do // a research at the next iteration with a bigger aspiration window. rml.set_move_score(i, -VALUE_INFINITE); continue; }
Sven
-
- Posts: 4052
- Joined: Thu May 15, 2008 9:57 pm
- Location: Berlin, Germany
- Full name: Sven Schüle
Re: Stockfish-1.5 Detects mate then changes mind?
Found my fault. After detecting a fail high ("aspiration fail high"), all remaining moves are assigned -VALUE_INFINITE as move score in the root move list but not searched. So this is the "quick return", although it is not done with a "break" or "return" since some code has to be executed for the remaining root moves.Sven Schüle wrote:Within this piece of code, which is from the currently published Stockfish 1.5 source, I wonder what the real intention is: either "quickly return", as stated in the comment, or "continue" (with the remaining moves). Only one of both can be meant, but which one?mcostalba wrote:Code: Select all
if (alpha >= beta) { // We failed high, invalidate and skip next moves, leave node-counters // and beta-counters as they are and quickly return, we will try to do // a research at the next iteration with a bigger aspiration window. rml.set_move_score(i, -VALUE_INFINITE); continue; }
Sven
Sorry for making noise but it was not immediately obvious for me.
Sven
-
- Posts: 20943
- Joined: Mon Feb 27, 2006 7:30 pm
- Location: Birmingham, AL
Re: Stockfish-1.5 Detects mate then changes mind?
The above is not limited to one search depth. At depth=16 you fail low and decide you are losing a rook. At depth=17 you fail high on a move after the first move. Now you abort, and start depth=18. There may well be a much better move at depth=17 if you had just taken the time to find it. By skipping it, you start a search that is hard enough to complete that you might not see this.Uri Blass wrote:zamar wrote:Currently we stay with the original aspiration window no matter what happens. We don't ever research fail-high/low with bigger window, just allocate much extra time to (hopefully) be able to complete the next iteration. It works surpisingly often, but sometimes when facing a big fail low (like +4 -> +1), it really sucks.
Simplified code for root_search() goes like this:
root_search is called by standard iterative deepening routine which calculates the window [alpha, beta] based on previous iterations.Code: Select all
root_search(alpha, beta) { for (int i = 0; i < RootMoveCount && alpha < beta; i++) { if (i == 0) value = -search_pv(-beta, -alpha) else { value = -search(-alpha-1,-alpha) if (value > alpha) value = -search_pv(-beta,-alpha) } if (i == 0 || value > alpha) best_i = i if (value > alpha) alpha = value } return alpha; }
Maybe I do not understand this code but based on my understanding
the problem that bob discribed should not happen because you do not skip the rest of the moves in every fail high but only in fail high that is above beta
Bob's words are:
"You fail low at the root as the "best" moves loses a rook. You search and the next move fails high. Once you resolve it you realize it just loses a knight."
I think that in this case you continue to search at the same depth because assuming that
beta=0 before the fail low it continue to be 0 until the end of the iteration.
The only fail high that cause skipping the rest of the moves is fail high that cause you to get a positive score.
Uri
I'm not a fan of the idea of pruning at the root like this, and that is exactly what is happening with this approach. We throw the rest of the moves out the window, and start the next iteration.
-
- Posts: 10874
- Joined: Thu Mar 09, 2006 12:37 am
- Location: Tel-Aviv Israel
Re: Stockfish-1.5 Detects mate then changes mind?
If you fail low at depth 16 and do not find a better move than losing a rook at that depth then you probably cannot find a saving move at depth 17.bob wrote:The above is not limited to one search depth. At depth=16 you fail low and decide you are losing a rook. At depth=17 you fail high on a move after the first move. Now you abort, and start depth=18. There may well be a much better move at depth=17 if you had just taken the time to find it. By skipping it, you start a search that is hard enough to complete that you might not see this.Uri Blass wrote:zamar wrote:Currently we stay with the original aspiration window no matter what happens. We don't ever research fail-high/low with bigger window, just allocate much extra time to (hopefully) be able to complete the next iteration. It works surpisingly often, but sometimes when facing a big fail low (like +4 -> +1), it really sucks.
Simplified code for root_search() goes like this:
root_search is called by standard iterative deepening routine which calculates the window [alpha, beta] based on previous iterations.Code: Select all
root_search(alpha, beta) { for (int i = 0; i < RootMoveCount && alpha < beta; i++) { if (i == 0) value = -search_pv(-beta, -alpha) else { value = -search(-alpha-1,-alpha) if (value > alpha) value = -search_pv(-beta,-alpha) } if (i == 0 || value > alpha) best_i = i if (value > alpha) alpha = value } return alpha; }
Maybe I do not understand this code but based on my understanding
the problem that bob discribed should not happen because you do not skip the rest of the moves in every fail high but only in fail high that is above beta
Bob's words are:
"You fail low at the root as the "best" moves loses a rook. You search and the next move fails high. Once you resolve it you realize it just loses a knight."
I think that in this case you continue to search at the same depth because assuming that
beta=0 before the fail low it continue to be 0 until the end of the iteration.
The only fail high that cause skipping the rest of the moves is fail high that cause you to get a positive score.
Uri
I'm not a fan of the idea of pruning at the root like this, and that is exactly what is happening with this approach. We throw the rest of the moves out the window, and start the next iteration.
The situation that you describe can happen but I guess that it is relatively rare and I guess that in near 99% of the cases the fail high that cause skipping the rest of the moves comes from non losing positions.
Uri
-
- Posts: 20943
- Joined: Mon Feb 27, 2006 7:30 pm
- Location: Birmingham, AL
Re: Stockfish-1.5 Detects mate then changes mind?
While it is not common, I do see it regularly. Score suddenly drops, then starts to climb over the next few iterations. Either way, this appears to be a problem. I did not look at their code, but assume they use aspiration search (can't think of a single reason why one would not). With aspiration search, score > beta is still not enough justification, in my mind, to skip the rest of the moves and start a new search. You can still fail low on the first move, reset the search window, and now start failing high on beta, for multiple moves. Except that if you give up after the first fail high and go to the next iteration, it is more than a little likely that you will be deep enough that you will never find the true best move, because the fail-high move will take so long to search.Uri Blass wrote:If you fail low at depth 16 and do not find a better move than losing a rook at that depth then you probably cannot find a saving move at depth 17.bob wrote:The above is not limited to one search depth. At depth=16 you fail low and decide you are losing a rook. At depth=17 you fail high on a move after the first move. Now you abort, and start depth=18. There may well be a much better move at depth=17 if you had just taken the time to find it. By skipping it, you start a search that is hard enough to complete that you might not see this.Uri Blass wrote:zamar wrote:Currently we stay with the original aspiration window no matter what happens. We don't ever research fail-high/low with bigger window, just allocate much extra time to (hopefully) be able to complete the next iteration. It works surpisingly often, but sometimes when facing a big fail low (like +4 -> +1), it really sucks.
Simplified code for root_search() goes like this:
root_search is called by standard iterative deepening routine which calculates the window [alpha, beta] based on previous iterations.Code: Select all
root_search(alpha, beta) { for (int i = 0; i < RootMoveCount && alpha < beta; i++) { if (i == 0) value = -search_pv(-beta, -alpha) else { value = -search(-alpha-1,-alpha) if (value > alpha) value = -search_pv(-beta,-alpha) } if (i == 0 || value > alpha) best_i = i if (value > alpha) alpha = value } return alpha; }
Maybe I do not understand this code but based on my understanding
the problem that bob discribed should not happen because you do not skip the rest of the moves in every fail high but only in fail high that is above beta
Bob's words are:
"You fail low at the root as the "best" moves loses a rook. You search and the next move fails high. Once you resolve it you realize it just loses a knight."
I think that in this case you continue to search at the same depth because assuming that
beta=0 before the fail low it continue to be 0 until the end of the iteration.
The only fail high that cause skipping the rest of the moves is fail high that cause you to get a positive score.
Uri
I'm not a fan of the idea of pruning at the root like this, and that is exactly what is happening with this approach. We throw the rest of the moves out the window, and start the next iteration.
The situation that you describe can happen but I guess that it is relatively rare and I guess that in near 99% of the cases the fail high that cause skipping the rest of the moves comes from non losing positions.
Uri