I wondered if anyone had come across this issue:
When I run Stockfish 1.3.1_JA in the Chessbase GUI as an analysis engine, it offers up two different lines of analysis but scores both lines identically.
Stockfish v1.3.1_JA running in Fritz GUI
Moderator: Ras
-
- Posts: 2053
- Joined: Wed Mar 08, 2006 8:30 pm
Re: Stockfish v1.3.1_JA running in Fritz GUI
Funny... and true (multi-variation analysis) for 1.3 and 1.3.1
Analysis by Stockfish 1.3 JA:
1. +/= (0.56): 1.Bxa3 e5 2.Bb2 d6 3.e3 Qg5 4.Nf3 Qg6 5.Bc4 Nc6 6.0-0 Nf6 7.d4 e4 8.Nh4 Qg4 9.d5 Qxd1 10.Raxd1 Ne5 11.Bxe5 dxe5 12.Rb1
2. +/= (0.56): 1.d4 Ra4
3. +/= (0.56): 1.e3 Ra4
4. +/= (0.56): 1.Bb2 Ra4
5. +/= (0.56): 1.e4 Ra5
6. +/= (0.56): 1.Nf3 Ra5
1.2 did not have that bug.

Analysis by Stockfish 1.3 JA:
1. +/= (0.56): 1.Bxa3 e5 2.Bb2 d6 3.e3 Qg5 4.Nf3 Qg6 5.Bc4 Nc6 6.0-0 Nf6 7.d4 e4 8.Nh4 Qg4 9.d5 Qxd1 10.Raxd1 Ne5 11.Bxe5 dxe5 12.Rb1
2. +/= (0.56): 1.d4 Ra4
3. +/= (0.56): 1.e3 Ra4
4. +/= (0.56): 1.Bb2 Ra4
5. +/= (0.56): 1.e4 Ra5
6. +/= (0.56): 1.Nf3 Ra5
1.2 did not have that bug.
Re: Stockfish v1.3.1_JA running in Fritz GUI
I assume that the top line is the optimal one!?
-
- Posts: 2053
- Joined: Wed Mar 08, 2006 8:30 pm
Re: Stockfish v1.3.1_JA running in Fritz GUI
The sample (actually illegal
) position was:
[d]rnbqkbn1/pppppppp/8/8/8/r7/P1PPPPPP/R1BQKBNR w KQq - 0 1

[d]rnbqkbn1/pppppppp/8/8/8/r7/P1PPPPPP/R1BQKBNR w KQq - 0 1
-
- Posts: 613
- Joined: Sun Jan 18, 2009 7:03 am
Re: Stockfish v1.3.1_JA running in Fritz GUI
This looks like my mistake. The bug went in with new aspiration window search code. This happens when you concentrate only improving program's strength and forget to worry about other important features 
Marco, I strongly suspect that you end up here sooner or later. Fix is oneliner:
--- a/src/search.cpp
+++ b/src/search.cpp
@@ -897,7 +897,7 @@ namespace {
if (i < MultiPV)
{
- value = -search_pv(pos, ss, -beta, -alpha, newDepth, 1, 0);
+ value = -search_pv(pos, ss, -beta, MultiPV == 1 ? -alpha : VALUE_INFINITE, newDepth, 1, 0);
// If the value has dropped a lot compared to the last iteration,
// set the boolean variable Problem to true. This variable is used
// for time managment: When Problem is true, we try to complete the

Marco, I strongly suspect that you end up here sooner or later. Fix is oneliner:
--- a/src/search.cpp
+++ b/src/search.cpp
@@ -897,7 +897,7 @@ namespace {
if (i < MultiPV)
{
- value = -search_pv(pos, ss, -beta, -alpha, newDepth, 1, 0);
+ value = -search_pv(pos, ss, -beta, MultiPV == 1 ? -alpha : VALUE_INFINITE, newDepth, 1, 0);
// If the value has dropped a lot compared to the last iteration,
// set the boolean variable Problem to true. This variable is used
// for time managment: When Problem is true, we try to complete the
Joona Kiiski
-
- Posts: 4669
- Joined: Sun Mar 12, 2006 2:40 am
- Full name: Eelco de Groot
Ancalagon's version of Stockfish v1.3.1_JA search
Thanks for Stockfish 1.3.1 Joona!zamar wrote:This looks like my mistake. The bug went in with new aspiration window search code. This happens when you concentrate only improving program's strength and forget to worry about other important features
Marco, I strongly suspect that you end up here sooner or later. Fix is oneliner:
--- a/src/search.cpp
+++ b/src/search.cpp
@@ -897,7 +897,7 @@ namespace {
if (i < MultiPV)
{
- value = -search_pv(pos, ss, -beta, -alpha, newDepth, 1, 0);
+ value = -search_pv(pos, ss, -beta, MultiPV == 1 ? -alpha : VALUE_INFINITE, newDepth, 1, 0);
// If the value has dropped a lot compared to the last iteration,
// set the boolean variable Problem to true. This variable is used
// for time managment: When Problem is true, we try to complete the
It is quite by accident, but the experimental version of Stockfish's search.cpp I am using at the moment already repaired this Multi_PV window problem in a way, although I'm not sure the windows it uses are correct always and had not tested the Multi PV option yet. It is just an experiment. It does something of a second pass over your aspiration windows Joona. When I programmed it it seemed more or less clear to me but when I look at it again I have great difficulty understanding what it is all about


Also it uses now search_pv where most programs use the nullwindow search, and vice versa

Code: Select all
const Value NullMoveMargin = Value(0x350);
Code: Select all
// root_search() is the function which searches the root node. It is
// similar to search_pv except that it uses a different move ordering
// scheme (perhaps we should try to use this at internal PV nodes, too?)
// and prints some information to the standard output.
Value root_search(Position &pos, SearchStack ss[], RootMoveList &rml, Value alpha, Value beta) {
Value oldAlpha = alpha;
Value value, oldvalue, PV_value;
Bitboard dcCandidates = pos.discovered_check_candidates(pos.side_to_move());
// Loop through all the moves in the root move list
for (int i = 0; i < rml.move_count() && !AbortSearch; 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;
}
int64_t nodes, nodes_before, nodes_after, nodes_minimum ;
Move move;
StateInfo st;
Depth ext, newDepth, LateMoveDepth;
RootMoveNumber = i + 1;
FailHigh = false;
// Remember the node count before the move is searched. The node counts
// are used to sort the root moves at the next iteration.
nodes = nodes_searched();
// Reset beta cut-off counters
BetaCounter.clear();
// Pick the next root move, and print the move and the move number to
// the standard output.
move = ss[0].currentMove = rml.get_move(i);
if (current_search_time() >= 1000)
std::cout << "info currmove " << move
<< " currmovenumber " << i + 1 << std::endl;
// Decide search depth for this move
bool dangerous;
ext = extension(pos, move, true, pos.move_is_capture(move), pos.move_is_check(move), false, false, &dangerous);
newDepth = (Iteration - 2) * OnePly + ext + InitialDepth;
// Make the move, and search it
pos.do_move(move, st, dcCandidates);
if (i < MultiPV)
{
if (Iteration <= 45)
{
Value gamma = Value(0x100);
if (Iteration >= 6) gamma = alpha;
value = -search(pos, ss, -gamma, newDepth + 1, 1, true, 0);
if (value > gamma && alpha <= gamma) alpha = Value((gamma + value) >> 1);
else alpha = Value((alpha + value - 0x300) >> 1);
}
value = -search_pv(pos, ss, -beta, -alpha, newDepth, 1, 0);
// If the value has dropped a lot compared to the last iteration,
// set the boolean variable Problem to true. This variable is used
// for time management: When Problem is true, we try to complete the
// current iteration before playing a move.
Problem = (Iteration >= 2 && value <= IterationInfo[Iteration-1].value - ProblemMargin);
if (Problem && StopOnPonderhit)
StopOnPonderhit = false;
}
else
{
value = -search(pos, ss, -alpha, newDepth, 1, true, 0);
oldvalue = value;
value = -search(pos, ss, -alpha, newDepth + 2, 1, true, 0);
if (value > alpha)
{
// Fail high! Set the boolean variable FailHigh to true, and
// re-search the move with a big window. The variable FailHigh is
// used for time management: We try to avoid aborting the search
// prematurely during a fail high research.
FailHigh = true;
value = -search_pv(pos, ss, -beta, -alpha, newDepth, 1, 0);
value = -search(pos, ss, -alpha, newDepth + 3, 1, true, 0);
}
else
{
nodes_minimum = 0;
PV_value = -search_pv(pos, ss, -beta, -alpha, newDepth - 1, 1, 0);
LateMoveDepth = newDepth;
if (value - oldvalue >= 50 || PV_value > oldvalue)
{
value = -search(pos, ss, -alpha, newDepth + 3, 1, true, 0);
PV_value = -search_pv(pos, ss, -beta, -alpha, newDepth, 1, 0);
if (value - oldvalue >= 75 || value > alpha || PV_value > alpha)
{
FailHigh = true;
oldvalue = value;
value = -search(pos, ss, -alpha, newDepth + 5, 1, true, 0);
}
}
else while (nodes_minimum < 10000 && PV_value < alpha && LateMoveDepth < MaxDepth)
{
nodes_before = nodes_searched();
PV_value = -search_pv(pos, ss, - VALUE_INFINITE, -alpha, LateMoveDepth, 1, 0);
nodes_after = nodes_searched();
LateMoveDepth = LateMoveDepth + 1;
nodes_minimum = nodes_after - nodes_before;
if (PV_value > value) value = PV_value;
}
}
}
pos.undo_move(move);
// Finished searching the move.

It is possible though that all this does not work with more threads Joona, I have not given it any thought and can't test it yet here. Sorry!
[/caveat]
Important Vas quote in this respect - using nodes_searched() -, they have a list in the Rybka forum but this one is not in it:
Regards, Eelco
Quote from GCP:Depth is a poor measure of search quality, time is much better.
Now, in case of chess, if you split the set of moves equally between CPUs, each move is guaranteed to get pretty much the same effort spent to it. This might result in different depths, but who cares if the effort spent is equal? So, in the clustering-root-unsynchronised case, it seems totally obvious to me that you would just pick the best scoring move, ignoring depth totally.
Vas
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
place. Therefore, if you write the code as cleverly as possible, you
are, by definition, not smart enough to debug it.
-- Brian W. Kernighan
-
- Posts: 2684
- Joined: Sat Jun 14, 2008 9:17 pm
Re: Stockfish v1.3.1_JA running in Fritz GUI
Thanks, seems a wise thing to dozamar wrote: {
- value = -search_pv(pos, ss, -beta, -alpha, newDepth, 1, 0);
+ value = -search_pv(pos, ss, -beta, MultiPV == 1 ? -alpha : VALUE_INFINITE, newDepth, 1, 0);

BTW do you think new aspiration window _could_ have an impact on the SMP code? As you probably have read first results _seem_ to show a regression when going SMP.
-
- Posts: 613
- Joined: Sun Jan 18, 2009 7:03 am
Re: Stockfish v1.3.1_JA running in Fritz GUI
I've thought about a lot of this assumed SMP-regression lately and I haven't found any connection between aspiration stuff and SMP, but this is of course this is one of the things to be tested when I get my quad back from repair...mcostalba wrote:Thanks, seems a wise thing to dozamar wrote: {
- value = -search_pv(pos, ss, -beta, -alpha, newDepth, 1, 0);
+ value = -search_pv(pos, ss, -beta, MultiPV == 1 ? -alpha : VALUE_INFINITE, newDepth, 1, 0);
BTW do you think new aspiration window _could_ have an impact on the SMP code? As you probably have read first results _seem_ to show a regression when going SMP.
I've scanned through the Changelog between 1.2->1.3 to find the reason for (possible) SMP-regression and the only _wild_guess_ I've got is this:
* I've heard top guys talking that when the number of CPUs grows the shared memory access can become a bottleneck (top guys talk about cachelines and other stuff I know nothing about). The way we changed QSearch TT-stuff make each thread to read/write to RAM more often than what it was in 1.2. Could it be that threads get jammed trying to access same memory segments simultaneously and being on the way of each other?
Really just a wild guess and likely to be wrong

Joona Kiiski
-
- Posts: 613
- Joined: Sun Jan 18, 2009 7:03 am
Re: Ancalagon's version of Stockfish v1.3.1_JA search
I'm not the right person to thank, but you are welcome anywayEelco de Groot wrote: Thanks for Stockfish 1.3.1 Joona!

Thanks! I'll try to understand your codeIt is quite by accident, but the experimental version of Stockfish's search.cpp I am using at the moment already repaired this Multi_PV window problem in a way, although I'm not sure the windows it uses are correct always and had not tested the Multi PV option yet. It is just an experiment. It does something of a second pass over your aspiration windows Joona. When I programmed it it seemed more or less clear to me but when I look at it again I have great difficulty understanding what it is all about![]()
![]()

If your code improves single core stuff, it'll also improve SMP-stuff, cause we are not splitting in root.[caveat]![]()
It is possible though that all this does not work with more threads Joona, I have not given it any thought and can't test it yet here. Sorry!
[/caveat]
Joona Kiiski
-
- Posts: 2684
- Joined: Sat Jun 14, 2008 9:17 pm
Re: Stockfish v1.3.1_JA running in Fritz GUI
I could try to test speed nodes / sec with 1 and 2 threads (I have an Intel Core 2 Duo) so to see if scaling is better when disabling TT in qsearch.zamar wrote:I've thought about a lot of this assumed SMP-regression lately and I haven't found any connection between aspiration stuff and SMP, but this is of course this is one of the things to be tested when I get my quad back from repair...mcostalba wrote:Thanks, seems a wise thing to dozamar wrote: {
- value = -search_pv(pos, ss, -beta, -alpha, newDepth, 1, 0);
+ value = -search_pv(pos, ss, -beta, MultiPV == 1 ? -alpha : VALUE_INFINITE, newDepth, 1, 0);
BTW do you think new aspiration window _could_ have an impact on the SMP code? As you probably have read first results _seem_ to show a regression when going SMP.
I've scanned through the Changelog between 1.2->1.3 to find the reason for (possible) SMP-regression and the only _wild_guess_ I've got is this:
* I've heard top guys talking that when the number of CPUs grows the shared memory access can become a bottleneck (top guys talk about cachelines and other stuff I know nothing about). The way we changed QSearch TT-stuff make each thread to read/write to RAM more often than what it was in 1.2. Could it be that threads get jammed trying to access same memory segments simultaneously and being on the way of each other?
Really just a wild guess and likely to be wrong
What do you think?
One thing that make me think more of a bug as a possible reason is that tests report didn't talk about speed regressions.
I would think if speed is the problem, as example due to a bottleneck in memory access, then this would have been already posted by testers, for them is easy to spot a non linear increase in node count when moving from single CPU to their beefy quads....hmmmm....