Solving a fail low situation at the root

Discussion of chess software programming and technical issues.

Moderators: hgm, Rebel, chrisw

gladius
Posts: 568
Joined: Tue Dec 12, 2006 10:10 am
Full name: Gary Linscott

Re: Solving a fail low situation at the root

Post by gladius »

Eelco de Groot wrote:Correction for Gary: the discussion about returning hashhits in PV nodes was not in this thread that is more about Stockfish' Fail High behaviour, but around the same time and also on Open Chess, I found a post from Marco referring to Stockfish 2.0.1 so that must have been the first version.

Eelco
Ok, thanks Eelco. I wonder how different the behavior is nowadays than old versions of SF though. SF 1.8 is almost a completely different engine than current SF.

But, if it really busts up analysis behavior, maybe the PV hash needs to come back :).
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: Solving a fail low situation at the root

Post by bob »

gladius wrote:
bob wrote:
gladius wrote:
bob wrote:
gladius wrote:
bob wrote:Here's what I responded to:
Does Stockfish avoid fetching pv scores from the hash?
I responded "yes it does disallow exact hash hits at PV nodes."

From your comment, it seems that this is still being done. Getting rid of the hash PV reconstruction is a good idea. But not allowing exact hash matches is, IMHO, foolish when there is a very simple fix for this problem that works, without ignoring hash hits of any kind.
We are going in circles here :). Before last week, it *did* allow them. And reconstructed the PV from hash.

SF just started to disallow exact hash hits when the triangular array was introduced last week. That's what I was trying to point out.

RE: not allowing them, at least at the fishtest TC, there was no ELO benefit. So, that's why we decided not to go with a PV TT cache.
OK, first, the oldest stockfish I have is 1.8. Here is a direct comment from the code:

// Transposition table lookup. At PV nodes, we don't use the TT for
// pruning, but only for move ordering.

Which says that the TT is ignored (scores) at PV nodes as best I can understand.

Here's the code that goes with that:

if (!PvNode && tte && ok_to_use_TT(tte, depth, beta, ply))
{
ss->currentMove = ttMove; // Can be MOVE_NONE
return value_from_tt(tte->value(), ply);
}

The value is not used at all if this is a "PvNode" it seems?

Which directly contradicts what you wrote. I did not dig through later versions, however, so anything could have changed. I just remembered the above from discussions here in recent months.

For the record, I consider it silly to treat PV and non-PV nodes differently, period. But specifically, treating them differently regarding how the table is used really makes no sense.

the PV hash was NOT to improve Elo, as previously explained. It was to provide correct PVs when you get exact entry hits along the PV. The intent was to give a user a real pv that takes you from the root position to the endpoint that produced the terminal node score, each and every time, without those short PVs that one always gets when using EXACT matches along the PV...
Ok, well, in the future, when you say "SF does this", please say the version you are referring to. Even as far back as SF 2.3.1, SF allowed this: https://github.com/official-stockfish/S ... h.cpp#L603.

I understand the reason behind the PV hash. I even implemented a similar version in SF to allow the PV pruning to remain. Then I measured PV pruning and it wasn't worth anything, so it was simpler to just turn it off and then the PV hash is not needed.
EXACT hits are rare. But they do happen. And each time you disallow one, you increase the cost of the search. I don't see any justification for doing that. The "but we can't measure any improvement" doesn't quite cut it for me, because the issue is quite obvious and the effect is a negative one, no matter how big or small it might be. However, everyone gets to make their own choices, good, bad or indifferent.
Yes, I agree, they do happen. The tradeoff is keeping them, and adding all the code for the PV hash, or turning them off, and then you don't need a PV hash. There are good arguments for both approaches.

If it was my personal project, I probably would have added the PV hash because it's a fun piece of code. But for SF, simpler is better.
PV hash is maybe 20 lines of code total? Not exactly a big effort. It took me 15 minutes to write, debug, and move on to the next issue.
bob
Posts: 20943
Joined: Mon Feb 27, 2006 7:30 pm
Location: Birmingham, AL

Re: Solving a fail low situation at the root

Post by bob »

gladius wrote:
Eelco de Groot wrote:Correction for Gary: the discussion about returning hashhits in PV nodes was not in this thread that is more about Stockfish' Fail High behaviour, but around the same time and also on Open Chess, I found a post from Marco referring to Stockfish 2.0.1 so that must have been the first version.

Eelco
Ok, thanks Eelco. I wonder how different the behavior is nowadays than old versions of SF though. SF 1.8 is almost a completely different engine than current SF.

But, if it really busts up analysis behavior, maybe the PV hash needs to come back :).
Some of the issues quoted are not really issues, either.

Repetitions are a problem if you allow ANY hash hits, period, not just exact hits. Because there is no path information when you do the probe to see if any position between the hit position and the endpoint that produced the position are repetitions or not. Ditto for 50 move problems. Only way to eliminate any of those is to eliminate ALL hash hits and just use it for move ordering, which will kill performance overall and especially in endgames.
User avatar
Eelco de Groot
Posts: 4561
Joined: Sun Mar 12, 2006 2:40 am
Full name:   

Re: Solving a fail low situation at the root

Post by Eelco de Groot »

Ron Murawski wrote:
Joerg Oster wrote:
Ron Murawski wrote:
Joerg Oster wrote:
Ron Murawski wrote:
Joerg Oster wrote:
Ron Murawski wrote:
Ron Murawski wrote:
xmas79 wrote: I'm also experimenting with asymetric windows, where on a fail low I widen only on the alpha side and on a fail high I widen only on the beta side, but I'm not sure of the implications. In the previous example, that means that on a fail low I will search with a window of [-100, -65].
For me asymmetric widening works best. I've found that the other, non-failing bound must be widened too, but only by a small amount compared to the widening of the failed bound.
A less-aggressive form of this idea has worked for Stockfish:

Code: Select all

Author: lucasart
Date: Sat Nov 8 10:47:56 2014 -0500
Timestamp: 1415461676

Be more optimistic in aspiration window

Be more optimistic wrt search instability, and set the unviolated bound
half window.

STC
LLR: 2.96 (-2.94,2.94) [-1.00,4.00]
Total: 16362 W: 3371 L: 3197 D: 9794

LTC
LLR: 2.94 (-2.94,2.94) [0.00,5.00]
Total: 21666 W: 3780 L: 3569 D: 14317

Bench: 6807896

Resolves #105
Yet the non-failing bound gets narrowed and not widened. Unlike you proposed. :)
Hi Joerg,

There is no inconsistency. Please re-read my original post.

Ron
Hi Ron,

I did, several times now. Still I always come to the same conclusion.
Assume beta is the non-failing bound. Narrowing means shift bound towards alpha, and widening means shift the bound towards +infinity. When you write the non-failing bound must be widened as well, I interpreted to do the latter. :D
Correct me if I'm wrong.
Hi Joerg,

Let's pretend that the current bounds are 0, 10 and there is a fail-high. Let us further suppose that at this point in the search the bounds usually get widened by 50. Normal alpha-beta with aspiration usually widens *both* bounds by this amount, so the new bounds would be -50, 60. The OP wondered if using new bounds of 0, 60 would work (all of the widening on one side). I suggested that a small widening of the non-failing bound is needed (based on testing that I did about 10 years ago). 'My' new bounds would be -12, 60. My reading of the comment written by Lucas ("set the unviolated bound half window") tells me that the new Stockfish bounds would be -25, 60, which has wider bounds than what I suggested.

Or are you saying that I misread the comment by Lucas?

Ron
Hi Ron,

to stick with your example, the new Stockfish would now set the bounds to 5, 60. So yes, it seems you misread Lucas' comment.
I also tried your idea, but it failed rather quickly. See here: http://tests.stockfishchess.org/tests/v ... 213f58926f
Hi Joerg,

It seems that my first understanding of widening of bounds was totally wrong. I originally (wrongly) widened both bounds. When I saw Lucas's comment:
"set the unviolated bound half window"
I (wrongly) assumed that the unviolated bound would only be widened by half the violated one.

In my own testing I reduced the non-failing bound adjustment close to the point of not changing it at all, but I never arrived there. :-(

I'm amazed that Lucas's patch doesn't cause a lot of search instability. Does a Stockfish TT hash entry keep track of the bounds? (I'm purposely not looking at Stockfish code until my engine is rewritten!) Does Stockfish avoid fetching pv scores from the hash?

Ron
I think that it probably does cause some search instability and that it also probably is worse when the hash table is saturated, which is on long searches. Going even deeper then, the re-searches of possible inferior first moves after a Fail Low of the PV move become more frequent and have a higher probability of Failing High into costly PV searches. Nevertheless proving at high depths that it costs Elo is not so easy. It may not.

It can't hurt to quote the condensed wisdom of Bruce Moreland on this topic, it deserves to be framed and hung on the wall :)
Search Instability

Without this, life would be fun


Search instability is something that happens when you try to write a program that is strong, as opposed to one that is perfect. There are many causes of instability, and I will discuss how various search enhancements can lead to instability, when I discuss those enhancements. A few other search techniques must take into account the possibility of instability.

An unstable search is one that returns results that don't make any sense. You have an alpha-beta window of (5, 25) and fail high. So you re-search with (24, INFINITY) and fail low. This shouldn't happen, because the fail-high indicated very clearly that the score should be 25 or better. How can you fail low?

Fact is, a lot of the things that make a chess program fast or strong do sleazy things that result in searches returning slightly different values when called with different windows, and if you aren't expecting the values you get, you can crash or have a bug that might make your program play a dumb move.

Some chess programmers can't handle the idea of search instability, and they are willing to let very good search techniques go in order to avoid it, or in order to think that they are avoiding it.

I wish it was possible to get rid of it completely, but as long as certain very basic techniques are used, it will be a problem. I think that the solution is to defend against crashes and bad behavior, then try to put it out of your mind.
I think there can be a a remedy that is fairly easy in the case of Stockfish, and I think it will work even better with the aggressive aspiration windows of the new patch. Because FL of the move at the Root are very different from FH, and trust in the PV increases with depth, trust in FL will fall with depth, there is no need for aspiration windows to be completely symmetric around the expected value of the move. Especially on deep searches. Just widen the margin a little downward, alpha can be a little lower below than beta is higher above the expected value.

In case of a Fail Low then Lucas' patch will even more aggressively cut below the previous best value ((alpha + beta)/2 is below the previous expected value of the move), but the chance of the initial Fail Low will be less. If it is a false Fail Low this smaller margin actually helps again, in theory, to achieve a Fail High after the Fail Low (Search Instability is good :))
Debugging is twice as hard as writing the code in the first
place. Therefore, if you write the code as cleverly as possible, you
are, by definition, not smart enough to debug it.
-- Brian W. Kernighan
User avatar
Eelco de Groot
Posts: 4561
Joined: Sun Mar 12, 2006 2:40 am
Full name:   

Re: Solving a fail low situation at the root

Post by Eelco de Groot »

It's probably clearer if you can see the code. (By the way this is not totally new code, it's been tried before) In practice, I changed only one number. Bench is unchanged (*) but on longer searches there is a functional change of course.

Code: Select all

            // Reset aspiration window starting size
            if (depth >= 5 * ONE_PLY)
            {
                delta = Value(16);
                alpha = std::max(RootMoves[PVIdx].prevScore - delta,-VALUE_INFINITE);
                beta  = std::min(RootMoves[PVIdx].prevScore + delta, VALUE_INFINITE);
            }
is changed to (search.cpp line 271-277):

Code: Select all

            // Reset aspiration window starting size
            if (depth >= 5 * ONE_PLY)
            {
                delta = Value(16);
                alpha = std::max(RootMoves[PVIdx].prevScore - std::max(delta, Value(depth/ONE_PLY)), -VALUE_INFINITE);
                beta  = std::min(RootMoves[PVIdx].prevScore + delta, VALUE_INFINITE);
            }
(*: For Rainbow Serpent:
Stockfish-master20141112_007
===========================
Total time (ms) : 5937
Nodes searched : 4787082
Nodes/second : 806313)
Debugging is twice as hard as writing the code in the first
place. Therefore, if you write the code as cleverly as possible, you
are, by definition, not smart enough to debug it.
-- Brian W. Kernighan
Joerg Oster
Posts: 937
Joined: Fri Mar 10, 2006 4:29 pm
Location: Germany

Re: Solving a fail low situation at the root

Post by Joerg Oster »

Eelco de Groot wrote:It's probably clearer if you can see the code. (By the way this is not totally new code, it's been tried before) In practice, I changed only one number. Bench is unchanged (*) but on longer searches there is a functional change of course.

Code: Select all

            // Reset aspiration window starting size
            if (depth >= 5 * ONE_PLY)
            {
                delta = Value(16);
                alpha = std::max(RootMoves[PVIdx].prevScore - delta,-VALUE_INFINITE);
                beta  = std::min(RootMoves[PVIdx].prevScore + delta, VALUE_INFINITE);
            }
is changed to (search.cpp line 271-277):

Code: Select all

            // Reset aspiration window starting size
            if (depth >= 5 * ONE_PLY)
            {
                delta = Value(16);
                alpha = std::max(RootMoves[PVIdx].prevScore - std::max(delta, Value(depth/ONE_PLY)), -VALUE_INFINITE);
                beta  = std::min(RootMoves[PVIdx].prevScore + delta, VALUE_INFINITE);
            }
(*: For Rainbow Serpent:
Stockfish-master20141112_007
===========================
Total time (ms) : 5937
Nodes searched : 4787082
Nodes/second : 806313)
Hi Eelco,

interesting. So with growing search depth you widen alpha more than at lower depths.
This seems rather strange to me and intuitively, I would just do the opposite. :)
Jörg Oster
User avatar
Eelco de Groot
Posts: 4561
Joined: Sun Mar 12, 2006 2:40 am
Full name:   

Re: Solving a fail low situation at the root

Post by Eelco de Groot »

Joerg Oster wrote:
Eelco de Groot wrote:It's probably clearer if you can see the code. (By the way this is not totally new code, it's been tried before) In practice, I changed only one number. Bench is unchanged (*) but on longer searches there is a functional change of course.

Code: Select all

            // Reset aspiration window starting size
            if (depth >= 5 * ONE_PLY)
            {
                delta = Value(16);
                alpha = std::max(RootMoves[PVIdx].prevScore - delta,-VALUE_INFINITE);
                beta  = std::min(RootMoves[PVIdx].prevScore + delta, VALUE_INFINITE);
            }
is changed to (search.cpp line 271-277):

Code: Select all

            // Reset aspiration window starting size
            if (depth >= 5 * ONE_PLY)
            {
                delta = Value(16);
                alpha = std::max(RootMoves[PVIdx].prevScore - std::max(delta, Value(depth/ONE_PLY)), -VALUE_INFINITE);
                beta  = std::min(RootMoves[PVIdx].prevScore + delta, VALUE_INFINITE);
            }
(*: For Rainbow Serpent:
Stockfish-master20141112_007
===========================
Total time (ms) : 5937
Nodes searched : 4787082
Nodes/second : 806313)
Hi Eelco,

interesting. So with growing search depth you widen alpha more than at lower depths.
This seems rather strange to me and intuitively, I would just do the opposite. :)
Hi Joerg!

I think it is best to just try this out on a position, of course it is good making a hypothesis of what you expect to find but if things can go either way in theory, then it brings you not much further to theorize. Just a couple of positions with a complicated variation seems best, not everything forced. It will be just a very limited test but it can help. The good thing about a deep search is that, everything else being equal (one search using more hash can be a concern for instance), small differences can accumulate over time.

Maybe what you think about is that the error margins in eval should become smaller if the PV converges to an optimum. Hopefully this is true in general or it makes not always sense to search deeper. But if the errormargin becomes smaller through convergence, the cost of a wider aspiration window also grows less quickly. The uncertainty will be in the last moves but you hope that these later moves have less effect on the eval than the moves close to the root.


The error margins will I think also grow if hash is saturated, this partially counters the above. Another factor goes in the other direction: consider a probable winning move. With a good search, eval will go up and up in each iteration. Alpha will also go up, wth the effect that other moves in the root are null window searched against a very high beta (alpha + 1). Their variations will be not far below this alpha and they will start to become looking almost winning moves. Now if something goes wrong in the principal variation the danger of one of these moves Failing High becomes very real. Suddenly they have to be PV-searched to a very high depth which is very costly, and the effort is wasted for a mediocre move, wastes TT table space etc.
Something going wrong in the PV is also very possible if the variation is complicated, for instance if you have to find a string of only moves, that just is getting longer with each iteration. Make one mistake in that PV that is difficult to correct in time, and suddenly the PV does not seem to win anymore. Huge drop in eval. There is at least a little buffer against simple null window Fail Lows out of the PV window if your alpha margin is larger.
Debugging is twice as hard as writing the code in the first
place. Therefore, if you write the code as cleverly as possible, you
are, by definition, not smart enough to debug it.
-- Brian W. Kernighan
User avatar
Eelco de Groot
Posts: 4561
Joined: Sun Mar 12, 2006 2:40 am
Full name:   

Re: Solving a fail low situation at the root

Post by Eelco de Groot »

I just wanted to add one testposition tried with the two versions of the code in modified Stockfish. I know one testposition is not enough, but it is more illustration. First the version with code as in Stockfish:

[D]2r4r/3n1pk1/pq1p1bp1/3B4/1p2P1N1/7P/PP1Q1PK1/3RR3 w - -

Engine: Sf20141112_005 MOD MP (512 MB)
by Tord Romstad, Marco Costalba and Joona Kiiski
.
.
.
.
24/28 0:10 +0.89++ 1.Re3 (29.693.504) 2699

24/28 0:12 +0.83-- 1.Re3 Ne5 (32.635.439) 2702

24/28 0:12 +0.91++ 1.Re3 (33.547.442) 2702

24/28 0:13 +0.98 1.Re3 Ne5 2.Nxf6 Kxf6 3.Rg3 Qc5
4.Bb7 Rc7 5.Bxa6 Kg7 6.Qxd6 Qxd6
7.Rxd6 Rh4 8.Re3 Rc2 9.Re2 Rxe2
10.Bxe2 Rxe4 11.Bb5 Nc4 12.Bxc4 Rxc4 (35.711.166) 2702

25/29 0:14 +1.04++ 1.Re3 (38.952.244) 2707

25/29 0:15 +0.98-- 1.Re3 Ne5 (41.636.564) 2716

25/29 0:16 +0.88-- 1.Re3 Ne5 (43.649.796) 2726

25/29 0:16 +0.96++ 1.Re3 (43.748.600) 2725

25/30 0:19 +1.08 1.Re3 Ne5 2.Nxf6 Kxf6 3.Rg3 Kg7 4.f4 Nc4
5.Qe2 Qc5 6.b3 Nb6 7.Bb7 Rc7 8.Bxa6 Qc2 (52.511.269) 2756

26/30 0:22 +1.05 1.Re3 Rcf8 2.Rb3 Qd8 3.f4 a5 4.a3 bxa3
5.Rxa3 Qe7 6.Rxa5 Nb6 7.Nxf6 Qxf6
8.Qd4 Qxd4 9.Rxd4 Nxd5 10.Raxd5 Rh4
11.f5 Rfh8 12.Rxd6 gxf5 13.exf5 Rxh3
14.Rg4+ (61.851.458) 2763

27/30 0:26 +1.11++ 1.Re3 (74.734.596) 2770

27/30 0:29 +1.05-- 1.Re3 Rcf8 (81.171.122) 2782

27/30 0:30 +1.11++ 1.Re3 (83.678.741) 2781

27/30 0:31 +1.03-- 1.Re3 Rcf8 (88.376.893) 2779

27/30 0:33 +1.03 1.Re3 Rcf8 2.Rb3 Qd8 3.f4 a5 4.a3 bxa3
5.bxa3 Rh4 6.Rb5 Nc5 7.Rxa5 Qd7 8.f5 Qe7
9.fxg6 Nxe4 10.Qc2 Nc3 11.Rf1 fxg6
12.Bc6 Be5 13.Rxf8 Rxg4+ 14.hxg4 (94.036.789) 2780

28/30 0:37 +0.97-- 1.Re3 Rcf8 (103.358.014) 2793

28/31 0:43 +1.03++ 1.Re3 (122.422.660) 2786

28/31 0:48 +0.97-- 1.Re3 Ne5 (135.300.231) 2793


28/40 0:59 +1.05++ 1.Bxf7 (168.610.046) 2845

28/40 1:02 +1.25++ 1.Bxf7 (179.391.952) 2857

28/41 1:05 +1.25 1.Bxf7 Kxf7 2.Qf4 g5 3.Qf5 Ke7 4.e5 Qc6+
5.Kh2 Bxe5+ 6.Nxe5 Nxe5 7.Rxe5+ dxe5
8.Qxe5+ Kf7 9.Qf5+ Ke8 10.Re1+ Kd8
11.Qxg5+ Kc7 12.Rc1 Qxc1 13.Qxc1+ Kb6
14.Qe3+ (186.348.815) 2859

29/43 1:09 +1.32++ 1.Bxf7 (199.577.299) 2870

29/43 1:13 +1.25-- 1.Bxf7 Kxf7 (211.155.288) 2872

29/43 1:15 +1.26 1.Bxf7 Kxf7 2.Qf4 g5 3.Qf5 Qc6 4.Kh2 Ke7
5.e5 Bxe5+ 6.Nxe5 Nxe5 7.Rxe5+ dxe5
8.Qxe5+ Kf7 9.Qf5+ Ke8 10.Re1+ Kd8
11.Qxg5+ Kc7 12.Rc1 Qxc1 13.Qxc1+ Kb6
14.Qe3+ (217.430.845) 2869

30/44 1:24 +1.25 1.Bxf7 Kxf7 2.Qf4 g5 3.Qf5 Qc6 4.Kh2 Ke7
5.e5 Bxe5+ 6.Nxe5 Nxe5 7.Rxe5+ dxe5
8.Qxe5+ Kf7 9.Qf5+ Ke8 10.Re1+ Kd8
11.Qxg5+ Kc7 12.Rc1 Qxc1 13.Qxc1+ Kb6
14.Qe3+ (241.541.572) 2860

31/44 1:37 +1.25 1.Bxf7 Kxf7 2.Qf4 g5 3.Qf5 Qc6 4.Kh2 Ke7
5.e5 Bxe5+ 6.Nxe5 Nxe5 7.Rxe5+ dxe5
8.Qxe5+ Kf7 9.Qf5+ Ke8 10.Re1+ Kd8
11.Qxg5+ Kc7 12.Rc1 Qxc1 13.Qxc1+ Kb6
14.Qe3+ (280.410.690) 2879

32/46 1:45 +1.32++ 1.Bxf7 (304.110.557) 2894

32/46 1:52 +1.25-- 1.Bxf7 Kxf7 (327.193.152) 2904

32/46 1:55 +1.32++ 1.Bxf7 (336.144.581) 2908

32/46 2:06 +1.36 1.Bxf7 Kxf7 2.Qf4 g5 3.Qf5 Qc6 4.Kh2 Ke7
5.e5 Bxe5+ 6.Nxe5 Nxe5 7.Rxe5+ dxe5
8.Qxe5+ Kf7 9.Qf5+ Ke8 10.Re1+ Kd8
11.Qxg5+ Kc7 12.Rc1 Qxc1 13.Qxc1+ Kb6
14.Qe3+ (371.423.141) 2925

33/48 2:23 +1.33 1.Bxf7 Kxf7 2.Qf4 g5 3.Qf5 Qc6 4.Kh2 Ke7
5.e5 Bxe5+ 6.Nxe5 Nxe5 7.Rxe5+ dxe5
8.Qxe5+ Kf7 9.Qf5+ Ke8 10.Re1+ Kd8
11.Qxg5+ Kc7 12.Rc1 Qxc1 13.Qxc1+ Kb6
14.Qe3+ (423.044.898) 2943

34/48 2:47 +1.39++ 1.Bxf7 (496.752.992) 2968

34/50 3:11 +1.45++ 1.Bxf7 (571.989.618) 2984

34/50 3:43 +1.55++ 1.Bxf7 Kxf7 (672.107.529) 3001

34/50 3:55 +1.47-- 1.Bxf7 Kxf7 (706.981.900) 3005

34/50 4:05 +1.51 1.Bxf7 Kxf7 2.Qf4 g5 3.Qf5 Qc6 4.Kh2 Ke7
5.e5 Bxe5+ 6.Nxe5 Nxe5 7.Rxe5+ dxe5
8.Qxe5+ Kf7 9.Qf5+ Ke8 10.Re1+ Kd8
11.Qxg5+ Kc7 12.Rc1 Qxc1 13.Qxc1+ Kb6
14.Qe3+ (738.839.981) 3006

35/50 4:49 +1.57++ 1.Bxf7 (878.237.384) 3029

35/51 5:03 +1.51-- 1.Bxf7 Kxf7 (919.845.584) 3027

35/51 5:22 +1.42-- 1.Bxf7 Kxf7 2.Qf4 g5 3.Qf5 Qc6 4.Kh2 Ke7
5.e5 Bxe5+ 6.Nxe5 Nxe5 7.Rxe5+ dxe5
8.Qxe5+ Kf7 9.Qf5+ Ke8 10.Re1+ Kd8
11.Qxg5+ Kc7 12.Rc1 Qxc1 13.Qxc1+ Kb6
14.Qe3+ (976.686.297) 3028

35/52 5:30 +1.50++ 1.Bxf7 (1.000.751.375) 3031

35/52 6:21 +1.70++ 1.Bxf7 (1.157.460.439) 3031

35/52 7:11 +1.71 1.Bxf7 Kxf7 2.Qf4 g5 3.Qf5 Ke7 4.e5 Qc6+
5.Kh2 Bxe5+ 6.Nxe5 Nxe5 7.Rxe5+ dxe5
8.Qxe5+ Kf7 9.Qf5+ Ke8 10.Re1+ Kd8
11.Qxg5+ Kc7 12.Rc1 Qxc1 13.Qxc1+ Kb7
14.Qg5 (1.313.466.827) 3041

36/52 8:33 +1.71 1.Bxf7 Kxf7 2.Qf4 g5 3.Qf5 Ke7 4.e5 Qc6+
5.Kh2 Bxe5+ 6.Nxe5 Nxe5 7.Rxe5+ dxe5
8.Qxe5+ Kf7 9.Qf5+ Ke8 10.Re1+ Kd8
11.Qxg5+ Kc7 12.Rc1 Qxc1 13.Qxc1+ Kb7
14.Qg5 (1.564.699.464) 3044

37/52 10:26 +1.71 1.Bxf7 Kxf7 2.Qf4 g5 3.Qf5 Ke7 4.e5 Qc6+
5.Kh2 Bxe5+ 6.Nxe5 Nxe5 7.Rxe5+ dxe5
8.Qxe5+ Kf7 9.Qf5+ Ke8 10.Re1+ Kd8
11.Qxg5+ Kc7 12.Rc1 Qxc1 13.Qxc1+ Kb7
14.Qg5 (1.916.985.452) 3061

38/54 12:56 +1.71 1.Bxf7 Kxf7 2.Qf4 g5 3.Qf5 Ke7 4.e5 Qc6+
5.Kh2 Bxe5+ 6.Nxe5 Nxe5 7.Rxe5+ dxe5
8.Qxe5+ Kf7 9.Qf5+ Ke8 10.Re1+ Kd8
11.Qxg5+ Kc7 12.Rc1 Qxc1 13.Qxc1+ Kb7
14.Qg5 (2.378.491.826) 3061

39/60 13:38 +1.65-- 1.Bxf7 Kxf7 (2.513.245.253) 3070

39/60 16:30 +1.71++ 1.Bxf7 (3.049.595.291) 3080

39/60 16:55 +1.65-- 1.Bxf7 Kxf7 (3.127.211.624) 3080

39/60 18:14 +1.68 1.Bxf7 Kxf7 2.Qf4 g5 3.Qf5 Ke7 4.e5 Qc6+
5.Kh2 Bxe5+ 6.Nxe5 Nxe5 7.Rxe5+ dxe5
8.Qxe5+ Kf7 9.Qf5+ Ke8 10.Re1+ Kd8
11.Qxg5+ Kc7 12.Rc1 Qxc1 13.Qxc1+ Kb6
14.Qe3+ (3.376.551.539) 3084

40/60 23:38 +1.74++ 1.Bxf7 (4.387.171.699) 3093

40/60 30:26 +1.81++ 1.Bxf7 (5.662.319.442) 3100

40/60 36:22 +1.74-- 1.Bxf7 Kxf7 (6.796.328.331) 3113

40/60 37:53 +1.60-- 1.Bxf7 Kxf7 (7.076.262.220) 3113

40/60 39:22 +1.71++ 1.Bxf7 (7.364.611.548) 3117

40/62 44:35 +1.84 1.Bxf7 Kxf7 2.Qf4 g5 3.Qf5 Qc6 4.Kh2 Ke7
5.e5 Bxe5+ 6.Nxe5 Nxe5 7.Rxe5+ dxe5
8.Qxe5+ Kf7 9.Qf5+ Ke8 10.Re1+ Kd8
11.Qxg5+ Kc7 12.Rc1 Qxc1 13.Qxc1+ Kb6
14.Qe3+ (8.365.802.474) 3126

41/62 53:45 +1.90++ 1.Bxf7 (10.008.752.425) 3103

41/62 55:14 +1.84-- 1.Bxf7 Kxf7 (10.260.755.458) 3095

41/62 58:09 +1.90++ 1.Bxf7 (10.744.949.414) 3079

41/62 59:16 +1.82-- 1.Bxf7 Kxf7 (10.939.877.438) 3076


41/62 61:29 +1.61-- 1.Bxf7 Kxf7 (11.330.473.172) 3070

41/62 65:05 +1.30-- 1.Bxf7 Kxf7 (11.980.556.037) 3067


41/62 118:33 +1.15 1.Rc1 Rxc1 2.Rxc1 Qd8 3.f4 Nc5 4.Rf1 Nd7
5.e5 Be7 6.f5 dxe5 7.fxg6 Nf6 8.Nxf6 Bxf6
9.gxf7 Rh5 10.Rd1 Qd7 11.Kf2 Rg5
12.Qxb4 Be7 13.Qe4 Qxh3 14.Rh1 (21.072.885.064) 2962


42/62 139:42 +1.21++ 1.Bxf7 (24.961.457.806) 2977

42/62 147:36 +1.27++ 1.Bxf7 (26.208.301.892) 2959

42/62 151:31 +1.36++ 1.Bxf7 (26.893.839.168) 2958

42/62 155:24 +1.50++ 1.Bxf7 (27.653.504.207) 2965

42/62 165:49 +1.71++ 1.Bxf7 (29.606.052.104) 2975


best move: Bd5xf7 time: 179:54.957 min n/s: 2.975.721 nodes: 32.313.546.378

The solution is not stable and a lot of time and transposition table space gets wasted. I have to say that, contrary to Stockfish, Rainbow Serpent does no singular extensions in PV nodes, and by my own theory singular extensions may help stabilize the PV (they extend the only_moves).

2r4r/3n1pk1/pq1p1bp1/3B4/1p2P1N1/7P/PP1Q1PK1/3RR3 w - -

Engine: Sf20141112_007 MOD MP (Q6700, 4 threads, 512 MB)
by Tord Romstad, Marco Costalba and Joona Kiiski

18/21 0:01 +0.99 1.Re3 Be7 2.Rb3 a5 3.a3 Ne5 4.axb4 a4
5.Rg3 Qa7 6.Nxe5 dxe5 7.Rf3 (2.718.314) 2367

19/23 0:01 +0.87 1.Re3 Ne5 2.Nxf6 Kxf6 3.a3 a5 4.Rb3 Kg7
5.axb4 axb4 6.Qxb4 Qxb4 7.Rxb4 Rc2
8.Rb7 g5 9.Bb3 (3.929.498) 2419

20/23 0:02 +1.04 1.Re3 Ne5 2.Nxf6 Kxf6 3.Bb3 Rhd8
4.Qd4 Qxd4 5.Rxd4 Nc6 6.Rf3+ Kg5
7.Rd5+ f5 8.exf5 Ne7 9.Ra5 Nxf5
10.Rd3 d5 11.Raxd5 Rxd5 12.Rxd5 (5.269.550) 2476

21/24 0:02 +1.04 1.Re3 Ne5 2.Nxf6 Kxf6 3.Bb3 Rhd8
4.Qd4 Qxd4 5.Rxd4 Nc6 6.Rf3+ Kg5
7.Rd5+ f5 8.exf5 Ne7 9.Ra5 Nxf5
10.Rd3 d5 11.Raxd5 Rxd5 12.Rxd5 (6.318.834) 2535
.
.
.
.
25/32 0:12 +0.92-- 1.Rc1 Rxc1 (34.448.702) 2772

25/32 0:12 +1.06 1.Rc1 Rxc1 2.Rxc1 Qd8 3.Qxb4 Be5
4.Nxe5 dxe5 5.Rc3 Nb6 6.Bc6 Nc8 (35.809.414) 2777

26/32 0:14 +1.12++ 1.Rc1 (39.643.443) 2792

26/32 0:18 +1.04-- 1.Rc1 Rcf8 (52.359.539) 2776

26/32 0:20 +0.94-- 1.Rc1 Rcf8 (56.727.752) 2779

26/32 0:22 +1.03++ 1.Rc1 (62.931.110) 2782

26/32 0:25 +0.93 1.Re3 Ne5 2.Nxf6 Kxf6 3.Bb3 Kg7
4.Qxd6 Qxd6 5.Rxd6 Rhd8 6.Rd5 Rxd5
7.exd5 Kf6 8.Kg3 Rd8 9.a3 Rb8 10.a4 Nd7
11.d6 Nc5 12.Rf3+ Ke5 13.d7 f6
14.Re3+ (70.596.243) 2787

27/32 0:28 +0.99++ 1.Re3 (79.254.562) 2783

27/32 0:31 +1.05++ 1.Re3 (87.510.331) 2765

27/32 0:36 +1.15++ 1.Rc1 (100.423.140) 2772

27/32 0:39 +1.23 1.Rc1 Rcf8 2.Red1 Qd8 3.f4 a5 4.Rc6 Nb8
5.Rc2 Nd7 6.Bc6 Nb6 7.Nxf6 Qxf6
8.Qxd6 Rd8 9.Qxf6+ Kxf6 10.Rxd8 Rxd8
11.Kf3 Rc8 12.Kg4 Ke7 13.e5 Nd5
14.Rc5 (110.481.729) 2779


28/38 0:51 +1.29++ 1.Bxf7 (145.905.329) 2808

28/39 0:54 +1.36++ 1.Bxf7 (154.114.742) 2824

28/39 0:58 +1.37 1.Bxf7 Kxf7 2.Qf4 g5 3.Qf5 Qc6 4.Kh2 Ke7
5.e5 Bxe5+ 6.Nxe5 Nxe5 7.Rxe5+ dxe5
8.Qxe5+ Kf7 9.Qf5+ Ke8 10.Re1+ Kd8
11.Qxg5+ Kc7 12.Rc1 Qxc1 13.Qxc1+ Kb6
14.Qe3+ (164.953.667) 2842

29/41 1:01 +1.43++ 1.Bxf7 (174.135.769) 2853

29/41 1:07 +1.39 1.Bxf7 Kxf7 2.Qf4 g5 3.Qf5 Qc6 4.Kh2 Ke7
5.e5 Bxe5+ 6.Nxe5 Nxe5 7.Rxe5+ dxe5
8.Qxe5+ Kf7 9.Qf5+ Ke8 10.Re1+ Kd8
11.Qxg5+ Kc7 12.Rc1 Qxc1 13.Qxc1+ Kb6
14.Qe3+ (191.671.416) 2853

30/42 1:25 +1.29 1.Bxf7 Kxf7 2.Qf4 g5 3.Qf5 Qc6 4.Kh2 Ke7
5.e5 Bxe5+ 6.Nxe5 Nxe5 7.Rxe5+ dxe5
8.Qxe5+ Kf7 9.Qf5+ Ke8 10.Re1+ Kd8
11.Qxg5+ Kc7 12.Rc1 Qxc1 13.Qxc1+ Kb6
14.Qe3+ (245.247.716) 2878

31/46 1:32 +1.35++ 1.Bxf7 (265.803.577) 2887

31/46 1:36 +1.41++ 1.Bxf7 (278.198.313) 2893

31/46 1:42 +1.34-- 1.Bxf7 Kxf7 (296.160.793) 2897

31/46 1:49 +1.29 1.Bxf7 Kxf7 2.Qf4 g5 3.Qf5 Qc6 4.Kh2 Ke7
5.e5 Bxe5+ 6.Nxe5 Nxe5 7.Rxe5+ dxe5
8.Qxe5+ Kf7 9.Qf5+ Ke8 10.Re1+ Kd8
11.Qxg5+ Kc7 12.Rc1 Qxc1 13.Qxc1+ Kb6
14.Qe3+ (317.680.044) 2899

32/46 2:06 +1.29 1.Bxf7 Kxf7 2.Qf4 g5 3.Qf5 Qc6 4.Kh2 Ke7
5.e5 Bxe5+ 6.Nxe5 Nxe5 7.Rxe5+ dxe5
8.Qxe5+ Kf7 9.Qf5+ Ke8 10.Re1+ Kd8
11.Qxg5+ Kc7 12.Rc1 Qxc1 13.Qxc1+ Kb6
14.Qe3+ (368.636.851) 2921

33/46 2:14 +1.36++ 1.Bxf7 (392.905.862) 2931

33/46 2:24 +1.42++ 1.Bxf7 (424.926.637) 2944

33/49 2:36 +1.51++ 1.Bxf7 (462.942.933) 2963

33/49 3:11 +1.45 1.Bxf7 Kxf7 2.Qf4 g5 3.Qf5 Qc6 4.Kh2 Ke7
5.e5 Bxe5+ 6.Nxe5 Nxe5 7.Rxe5+ dxe5
8.Qxe5+ Kf7 9.Qf5+ Ke8 10.Re1+ Kd8
11.Qxg5+ Kc7 12.Rc1 Qxc1 13.Qxc1+ Kb6
14.Qe3+ (570.704.102) 2985

34/49 3:44 +1.51++ 1.Bxf7 (672.179.589) 2993

34/49 3:58 +1.58++ 1.Bxf7 (715.213.363) 3001

34/49 4:22 +1.50-- 1.Bxf7 Kxf7 (789.411.475) 3004

34/49 4:37 +1.53 1.Bxf7 Kxf7 2.Qf4 g5 3.Qf5 Qc6 4.Kh2 Ke7
5.e5 Bxe5+ 6.Nxe5 Nxe5 7.Rxe5+ dxe5
8.Qxe5+ Kf7 9.Qf5+ Ke8 10.Re1+ Kd8
11.Qxg5+ Kc7 12.Rc1 Qxc1 13.Qxc1+ Kb6
14.Qe3+ (834.372.837) 3009

35/50 5:12 +1.60++ 1.Bxf7 (944.382.649) 3020

35/50 5:55 +1.60 1.Bxf7 Kxf7 2.Qf4 g5 3.Qf5 Qc6 4.Kh2 Ke7
5.e5 Bxe5+ 6.Nxe5 Nxe5 7.Rxe5+ dxe5
8.Qxe5+ Kf7 9.Qf5+ Ke8 10.Re1+ Kd8
11.Qxg5+ Kc7 12.Rc1 Qxc1 13.Qxc1+ Kb6
14.Qe3+ (1.080.162.255) 3038

36/50 6:51 +1.66++ 1.Bxf7 (1.257.728.425) 3057

36/51 7:06 +1.56-- 1.Bxf7 Kxf7 (1.303.074.234) 3057

36/52 7:23 +1.64++ 1.Bxf7 (1.354.760.746) 3055

36/52 7:34 +1.60 1.Bxf7 Kxf7 2.Qf4 g5 3.Qf5 Qc6 4.Kh2 Ke7
5.e5 Bxe5+ 6.Nxe5 Nxe5 7.Rxe5+ dxe5
8.Qxe5+ Kf7 9.Qf5+ Ke8 10.Re1+ Kd8
11.Qxg5+ Kc7 12.Rc1 Qxc1 13.Qxc1+ Kb7
14.Qg5 (1.387.486.862) 3052

37/52 9:19 +1.67++ 1.Bxf7 (1.712.576.986) 3061

37/52 10:43 +1.73++ 1.Bxf7 (1.977.525.071) 3072

37/53 11:17 +1.64-- 1.Bxf7 Kxf7 (2.090.559.513) 3083

37/53 12:03 +1.66 1.Bxf7 Kxf7 2.Qf4 g5 3.Qf5 Qc6 4.Kh2 Ke7
5.e5 Bxe5+ 6.Nxe5 Nxe5 7.Rxe5+ dxe5
8.Qxe5+ Kf7 9.Qf5+ Ke8 10.Re1+ Kd8
11.Qxg5+ Kc7 12.Rc1 Qxc1 13.Qxc1+ Kb6
14.Qe3+ (2.235.536.623) 3088

38/53 13:56 +1.72++ 1.Bxf7 (2.589.373.537) 3095

38/53 15:01 +1.62 1.Bxf7 Kxf7 2.Qf4 g5 3.Qf5 Qc6 4.Kh2 Ke7
5.e5 Bxe5+ 6.Nxe5 Nxe5 7.Rxe5+ dxe5
8.Qxe5+ Kf7 9.Qf5+ Ke8 10.Re1+ Kd8
11.Qxg5+ Kc7 12.Rc1 Qxc1 13.Qxc1+ Kb6
14.Qe3+ (2.796.326.358) 3102

39/53 18:14 +1.62 1.Bxf7 Kxf7 2.Qf4 g5 3.Qf5 Qc6 4.Kh2 Ke7
5.e5 Bxe5+ 6.Nxe5 Nxe5 7.Rxe5+ dxe5
8.Qxe5+ Kf7 9.Qf5+ Ke8 10.Re1+ Kd8
11.Qxg5+ Kc7 12.Rc1 Qxc1 13.Qxc1+ Kb6
14.Qe3+ (3.395.487.069) 3102

40/59 22:36 +1.62 1.Bxf7 Kxf7 2.Qf4 g5 3.Qf5 Qc6 4.Kh2 Ke7
5.e5 Bxe5+ 6.Nxe5 Nxe5 7.Rxe5+ dxe5
8.Qxe5+ Kf7 9.Qf5+ Ke8 10.Re1+ Kd8
11.Qxg5+ Kc7 12.Rc1 Qxc1 13.Qxc1+ Kb6
14.Qe3+ (4.232.185.158) 3119

41/59 29:17 +1.68++ 1.Bxf7 (5.440.306.341) 3096

41/59 33:57 +1.62 1.Bxf7 Kxf7 2.Qf4 g5 3.Qf5 Qc6 4.Kh2 Ke7
5.e5 Bxe5+ 6.Nxe5 Nxe5 7.Rxe5+ dxe5
8.Qxe5+ Kf7 9.Qf5+ Ke8 10.Re1+ Kd8
11.Qxg5+ Kc7 12.Rc1 Qxc1 13.Qxc1+ Kb6
14.Qe3+ (6.311.803.227) 3097

42/59 43:09 +1.68++ 1.Bxf7 (8.095.688.141) 3126

42/59 54:18 +1.75++ 1.Bxf7 (10.242.876.019) 3143

42/59 68:36 +1.84++ 1.Bxf7 (13.079.480.009) 3177

42/59 71:54 +1.75-- 1.Bxf7 Kxf7 (13.731.382.202) 3182

42/62 80:59 +1.83 1.Bxf7 Kxf7 2.Qf4 g5 3.Qf5 Qc6 4.Kh2 Ke7
5.e5 Bxe5+ 6.Nxe5 Nxe5 7.Rxe5+ dxe5
8.Qxe5+ Kf7 9.Qf5+ Ke8 10.Re1+ Kd8
11.Qxg5+ Kc7 12.Rc1 Qxc1 13.Qxc1+ Kb6
14.Qe3+ (15.528.392.326) 3195

43/62 93:01 +1.83 1.Bxf7 Kxf7 2.Qf4 g5 3.Qf5 Qc6 4.Kh2 Ke7
5.e5 Bxe5+ 6.Nxe5 Nxe5 7.Rxe5+ dxe5
8.Qxe5+ Kf7 9.Qf5+ Ke8 10.Re1+ Kd8
11.Qxg5+ Kc7 12.Rc1 Qxc1 13.Qxc1+ Kb6
14.Qe3+ (17.903.240.184) 3207

44/66 121:24 +1.89++ 1.Bxf7 (23.562.162.336) 3234

44/66 153:53 +1.95++ 1.Bxf7 (30.066.096.143) 3256

44/66 157:42 +1.86-- 1.Bxf7 Kxf7 (30.824.748.959) 3257

44/66 175:08 +1.95++ 1.Bxf7 (34.288.417.740) 3263

44/66 201:50 +1.84-- 1.Bxf7 Kxf7 (39.565.910.247) 3267

44/66 234:01 +2.00++ 1.Bxf7 (45.718.244.776) 3255

44/66 237:09 +1.76-- 1.Bxf7 Kxf7 (46.357.853.596) 3257

44/66 273:49 +2.09 1.Bxf7 Kxf7 2.Qf4 g5 3.Qf5 Qc6 4.Kh2 Ke7
5.e5 Bxe5+ 6.Nxe5 Nxe5 7.Rxe5+ dxe5
8.Qxe5+ Kf7 9.Qf5+ Ke8 10.Re1+ Kd8
11.Qxg5+ Kc7 12.Rc1 Qxc1 13.Qxc1+ Kb6
14.Qe3+ (53.421.450.307) 3251

45/69 316:16 +2.08 1.Bxf7 Kxf7 2.Qf4 g5 3.Qf5 Qc6 4.Kh2 Ke7
5.e5 Bxe5+ 6.Nxe5 Nxe5 7.Rxe5+ dxe5
8.Qxe5+ Kf7 9.Qf5+ Ke8 10.Re1+ Kd8
11.Qxg5+ Kc7 12.Rc1 Qxc1 13.Qxc1+ Kb6
14.Qe3+ (61.807.450.720) 3257

46/70 336:43 +1.90-- 1.Bxf7 Kxf7 (65.574.192.705) 3245

46/70 390:44 +2.02++ 1.Bxf7 (75.853.704.282) 3235

46/70 395:37 +1.93-- 1.Bxf7 Kxf7 (76.833.847.920) 3236

46/70 411:13 +2.02++ 1.Bxf7 (79.935.872.729) 3239

46/70 519:24 +2.18{!} 1.Bxf7 Kxf7 2.Qf4 g5 3.Qf5 Qc6 4.Kh2 Ke7
5.e5 Bxe5+ 6.Nxe5 Nxe5 7.Rxe5+ dxe5
8.Qxe5+ Kf7 9.Qf5+ Ke8 10.Re1+ Kd8
11.Qxg5+ Kc7 12.Rc1 Qxc1 13.Qxc1+ Kb7
14.Qg5 (101.396.024.566) 3253

47/70 534:31 +2.00-- 1.Bxf7 Kxf7 (104.477.195.536) 3257

47/70 546:50 +1.94-- 1.Bxf7 Kxf7 (107.168.578.458) 3266

47/70 558:37 +1.85-- 1.Bxf7 Kxf7 (109.417.755.310) 3264


47/70 576:21 +1.71-- 1.Bxf7 Kxf7 (112.975.233.296) 3266

47/70 606:50 +1.50-- 1.Bxf7 Kxf7 (118.765.990.818) 3261

47/70 692:18 +1.18-- 1.Bxf7 Kxf7 (135.151.374.746) 3253


47/70 739:02 +1.42++ 1.Bxf7 (143.901.062.804) 3245

best move: Bd5xf7 time: 813:01.153 min n/s: 3.245.253 nodes: 158.095.305.288

This code version 2, at least has a semblance of stability although in the end at depth 47 there was a very narrow escape with the eval in consecutive steps failing to +1.18 or less. But it was just enough to keep other moves below alpha now, at least this time.
Debugging is twice as hard as writing the code in the first
place. Therefore, if you write the code as cleverly as possible, you
are, by definition, not smart enough to debug it.
-- Brian W. Kernighan