I have not followed this discussion in detail, but I think this post contains some positions of the type you are looking for.mcostalba wrote:P.S: Regrading figuring out positions to excercize this code path, well it seems we are talking of potential stalemates when the ep move is the only possible and the code path has an effect only if the ep is losing....very difficult to figure out such positions with 5-men.
Question to syzygy author
Moderator: Ras
-
- Posts: 722
- Joined: Mon Apr 19, 2010 7:07 pm
- Location: Sweden
- Full name: Peter Osterlund
Re: Question to syzygy author
-
- Posts: 2684
- Joined: Sat Jun 14, 2008 9:17 pm
Re: Question to syzygy author
Thanks for your detailed explanations!syzygy wrote:Then we have probe_dtz()
In this case I went really in razor-mode here: first I have integrated the winning pawn move in search() then I fully simplified the whole probe_dtz():
https://github.com/official-stockfish/S ... .cpp#L1305
Now the next step is to verify I made it right

I will need some test positions for this (thanks Peter!), and is not trivial becuase many cases are extremely rare (with 5-men) and occur only on hand-crafted positions.
-
- Posts: 5672
- Joined: Tue Feb 28, 2012 11:56 pm
Re: Question to syzygy author
True, there cannot be many 5-piece positions with two en passant captures that would be stalemate without them.mcostalba wrote:Yes you are right! I have fixed the code to handle up to 2 ep moves (although it is very difficult to figure out such positions with 5-men, perhaps with 6-men).syzygy wrote: One problem is that there may be two en passant captures. However, I personally don't like this modification.
Probably 7 pieces are needed:
[d]7B/8/8/8/1pPp4/1K6/3N4/k7 b - c3 0 1
But still, it is better to have the logic correct.
I guess that in principle the idea to let probe_ab() take into account en passant is not that bad and might also simplify probe_dtz().Regrading optimization, unfortunatly this topic is 10% intuition and 90% measurement. I plan to correctly profile the code after I have simplified it and eventually I will (re)add an optimization if profile shows me it is useul. For the moment I prefer to proceed with the simplest code base (that usually it is also the fastest and best).
The major inefficiency that I see is the generation of all legal moves in every call to probe_ab(), even though checking for stalemate is only necessary in the very rare case that there all captures including at least one ep capture are losing and probe_wdl_table() returns a draw score. (In 99.999% of the calls to probe_ab() en passant will not be possible, because even probe_wdl() is normally called only after a capture.)
It is very rare, but it happens.P.S: Regrading figuring out positions to excercize this code path, well it seems we are talking of potential stalemates when the ep move is the only possible and the code path has an effect only if the ep is losing....very difficult to figure out such positions with 5-men.
-
- Posts: 5672
- Joined: Tue Feb 28, 2012 11:56 pm
Re: Question to syzygy author
6 pieces suffice:syzygy wrote:Probably 7 pieces are needed:
[d]7B/8/8/8/1pPp4/1K6/3N4/k7 b - c3 0 1
[d]8/8/8/8/1pPp4/1K1Q4/8/k7 b - c3 0 1
-
- Posts: 2684
- Joined: Sat Jun 14, 2008 9:17 pm
Re: Question to syzygy author
Just checked against [d]mcostalba wrote: Now the next step is to verify I made it right![]()
It works!

I have added some instrumenting code in a separate branch to verify that the output of WDl and DTZ probing is the same of the original reference. Indeed simple bench number is not feasible here because move generation inside TB probing code is done with a different ordering and this affects searched nodes, but the instrumented code ensures tha the return value and state of each probe call is equivalent to the reference one.
I have also added some debug UI commands 'wdl' and 'dtz' that probe respectively WDL and DTZ tables on the current position. This is useful to debug on a specific position.
-
- Posts: 5672
- Joined: Tue Feb 28, 2012 11:56 pm
Re: Question to syzygy author
You have probably noticed that there is a reason to do
and add 1 later to the "best positive dtz found" instead of doing immediately
In the latter case, a draw value would incorrecly turn into a win value.
Regarding the new ep logic, the way ep is dealt with around probe_wdl_table() seems correct.
However, there is a problem around the call to probe_dtz_table().
This function should not be called if the position without ep is a draw. But the current code will call probe_dtz_table() if the position is a loss (because of a losing ep capture) and the position without ep is a stalemate.
Code: Select all
if (wdl > 0)
dtz = -probe_dtz(pos, result);
Code: Select all
if (wdl > 0)
dtz = -probe_dtz(pos, result) + 1;
Regarding the new ep logic, the way ep is dealt with around probe_wdl_table() seems correct.
However, there is a problem around the call to probe_dtz_table().
This function should not be called if the position without ep is a draw. But the current code will call probe_dtz_table() if the position is a loss (because of a losing ep capture) and the position without ep is a stalemate.
-
- Posts: 5672
- Joined: Tue Feb 28, 2012 11:56 pm
Re: Question to syzygy author
Let's have a look at this code.
What it should do is signal to probe_dtz() that the best move is a winning capture or a winning pawn move (possibly cursed). This will normally be the case if alpha >= value and alpha > 0.
There is now the complication that we may have had to override "value" returned by probe_wdl_table() with epValue. But in this case we also want to signal to probe_dtz() that the best move is a capture (the ep capture).
I think there is no need to distinguish between WIN_CAPTURE and WIN_PAWN_MOVE (and whatever you would like to call the situation that the best move is a losing ep capture).
So:
And in probe_dtz():
(The last line is not valid C++, obviously.)
This might fix the problem I noticed above.
Code: Select all
// TB tables do not contain information on position with ep rights, so in
// this case probe_wdl_table could be wrong. In particular could be higher
// then epValue and if epValue is the only move then we are forced to play
// the losing ep capture.
if (epValue != WDLScoreNone && !moveCount)
value = epValue;
// Here alpha stores the best value out of the previous search
if (value > alpha)
return *result = (value == epValue && value > WDLDraw ? WIN_CAPTURE : OK), value;
if (bestMove && alpha > WDLDraw)
*result = (!CheckPawnMoves || pos.capture(bestMove)) ? WIN_CAPTURE : WIN_PAWN_MOVE;
else
*result = OK;
return alpha;
There is now the complication that we may have had to override "value" returned by probe_wdl_table() with epValue. But in this case we also want to signal to probe_dtz() that the best move is a capture (the ep capture).
I think there is no need to distinguish between WIN_CAPTURE and WIN_PAWN_MOVE (and whatever you would like to call the situation that the best move is a losing ep capture).
So:
Code: Select all
if (value == WDLDraw && !moveCount && epValue != WDLScoreNone && epValue < WDLDraw)
return *result = BEST_1_PLY, epValue;
if (alpha >= value)
return *result = alpha > WDLDraw ? BEST_1_PLY : OK, alpha;
return *result = OK, value;
Code: Select all
if (*result == BEST_1_PLY)
return -1 / -101 / 101 / 1 for wdl = -2 / -1 / 1 / 2;
This might fix the problem I noticed above.
-
- Posts: 5672
- Joined: Tue Feb 28, 2012 11:56 pm
Re: Question to syzygy author
In view of the lines that follow:syzygy wrote:And in probe_dtz():(The last line is not valid C++, obviously.)Code: Select all
if (*result == BEST_1_PLY) return -1 / -101 / 101 / 1 for wdl = -2 / -1 / 1 / 2;
This might fix the problem I noticed above.
Code: Select all
int dtz = 1 + (*result == BEST_1_PLY ? 0 : probe_dtz_table(pos, wdl, result));
-
- Posts: 2684
- Joined: Sat Jun 14, 2008 9:17 pm
Re: Question to syzygy author
Thanks! This greatly helped me.syzygy wrote: However, there is a problem around the call to probe_dtz_table().
I have rewritten that code, could you please give it a look? Thanks.
-
- Posts: 5672
- Joined: Tue Feb 28, 2012 11:56 pm
Re: Question to syzygy author
It seems to be correct.mcostalba wrote:Thanks! This greatly helped me.syzygy wrote: However, there is a problem around the call to probe_dtz_table().
I have rewritten that code, could you please give it a look? Thanks.