Designing an analysis friendly Stockfish?

Code, algorithms, languages, construction...
mcostalba
Posts: 91
Joined: Thu Jun 10, 2010 11:45 pm
Real Name: Marco Costalba

Re: Designing an analysis friendly Stockfish?

Post by mcostalba » Fri Feb 11, 2011 7:26 am

I try to confirm the result with 60000 10'' games now.
:idea: My electricity provider will be glad :idea:
Ok. Let's do electricity providers happy. I'm going to add in test queue this one:

Code: Select all

Subject: Use TT in PV also in qsearch()

Patch from Fruity:

http://www.open-chess.org/viewtopic.php?f=5&t=1042&start=160

Slightly reshuffled by me.
---

diff --git a/src/search.cpp b/src/search.cpp
--- a/src/search.cpp
+++ b/src/search.cpp
@@ -293,6 +293,20 @@ namespace {
   }
 
   template <NodeType PvNode>
+  inline bool ok_to_use_TT(const TTEntry* tte, Depth depth, Value alpha, Value beta, int ply) {
+
+    Value v = value_from_tt(tte->value(), ply);
+
+    return  (   tte->depth() >= depth
+             || v >= Max(value_mate_in(PLY_MAX), beta)
+             || v <= Min(value_mated_in(PLY_MAX), alpha))
+          &&
+            (PvNode ? tte->type() == VALUE_TYPE_EXACT
+                    : (   ((tte->type() & VALUE_TYPE_LOWER) && v >= beta)
+                       || ((tte->type() & VALUE_TYPE_UPPER) && v <= alpha)));
+  }
+
+  template <NodeType PvNode>
   Depth extension(const Position& pos, Move m, bool captureOrPromotion, bool moveIsCheck, bool singleEvasion, bool mateThreat, bool* dangerous);
 
   bool check_is_dangerous(Position &pos, Move move, Value futilityBase, Value beta, Value *bValue);
@@ -300,7 +314,6 @@ namespace {
   bool value_is_mate(Value value);
   Value value_to_tt(Value v, int ply);
   Value value_from_tt(Value v, int ply);
-  bool ok_to_use_TT(const TTEntry* tte, Depth depth, Value beta, int ply);
   bool connected_threat(const Position& pos, Move m, Move threat);
   Value refine_eval(const TTEntry* tte, Value defaultEval, int ply);
   void update_history(const Position& pos, Move move, Depth depth, Move movesSearched[], int moveCount);
@@ -991,14 +1004,10 @@ namespace {
     tte = TT.retrieve(posKey);
     ttMove = tte ? tte->move() : MOVE_NONE;
 
-    // At PV nodes, we don't use the TT for pruning, but only for move ordering.
-    // This is to avoid problems in the following areas:
-    //
-    // * Repetition draw detection
-    // * Fifty move rule detection
-    // * Searching for a mate
-    // * Printing of full PV line
-    if (!PvNode && tte && ok_to_use_TT(tte, depth, beta, ply))
+    // At PV nodes we check for exact scores, while at non-PV nodes we check for
+    // and return a fail high/low. Biggest advantage at probing at PV nodes is
+    // to have a smooth experience in analysis mode.
+    if (tte && ok_to_use_TT<PvNode>(tte, depth, alpha, beta, ply))
     {
         TT.refresh(tte);
         ss->bestMove = ttMove; // Can be MOVE_NONE
@@ -1443,7 +1452,7 @@ split_point_start: // At split points actual search starts from here
     tte = TT.retrieve(pos.get_key());
     ttMove = (tte ? tte->move() : MOVE_NONE);
 
-    if (!PvNode && tte && ok_to_use_TT(tte, ttDepth, beta, ply))
+    if (tte && ok_to_use_TT<PvNode>(tte, ttDepth, alpha, beta, ply))
     {
         ss->bestMove = ttMove; // Can be MOVE_NONE
         return value_from_tt(tte->value(), ply);
@@ -1849,22 +1858,6 @@ split_point_start: // At split points actual search starts from here
   }
 
 
-  // ok_to_use_TT() returns true if a transposition table score
-  // can be used at a given point in search.
-
-  bool ok_to_use_TT(const TTEntry* tte, Depth depth, Value beta, int ply) {
-
-    Value v = value_from_tt(tte->value(), ply);
-
-    return   (   tte->depth() >= depth
-              || v >= Max(value_mate_in(PLY_MAX), beta)
-              || v < Min(value_mated_in(PLY_MAX), beta))
-
-          && (   ((tte->type() & VALUE_TYPE_LOWER) && v >= beta)
-              || ((tte->type() & VALUE_TYPE_UPPER) && v < beta));
-  }
-
-
   // refine_eval() returns the transposition table score if
   // possible otherwise falls back on static position evaluation.
 
diff --git a/src/tt.cpp b/src/tt.cpp
--- a/src/tt.cpp
+++ b/src/tt.cpp
@@ -121,7 +121,7 @@ void TranspositionTable::store(const Key posKey, Value v, ValueType t, Depth d,
           continue;
 
       c1 = (replace->generation() == generation ?  2 : 0);
-      c2 = (tte->generation() == generation ? -2 : 0);
+      c2 = (tte->generation() == generation || tte->type() == VALUE_TYPE_EXACT ? -2 : 0);
       c3 = (tte->depth() < replace->depth() ?  1 : 0);
 
       if (c1 + c2 + c3 > 0)

BTW I have thought a bit about your result because was unexpected. It is true that leaf nodes are the most but PV leaf nodes are a real rarity and also in that case the advantage of returning from TT instead of performing the actual searching is minimal. But I have found a possible side effect that could be more important. At the beginning of the search we perform a qsearch<PvNode>() on the root position to have a startup scoring and so a startup ordering. It can happen that the startup ordering plays a role and in this case also your patch that uses TT hits in qsearch().

Prima
Posts: 328
Joined: Tue Dec 14, 2010 6:12 am

Re: Designing an analysis friendly Stockfish?

Post by Prima » Fri Feb 11, 2011 7:22 pm

gaard wrote:
Prima wrote:
gaard wrote:
gaard wrote:call "C:\Program Files (x86)\Intel\ComposerXE-2011\bit\iclvars.bat" intel64
Should be:

call "C:\Program Files (x86)\Intel\ComposerXE-2011\bin\iclvars.bat" intel64
Yes it is. As a matter of fact, I tried both PATH schemes:

Code: Select all

Option 1: PATH: ;C:\Program Files (x86)\Intel\ComposerXE-2011\bin\iclvars.bat" intel64 

Option 2: PATH: ;C:\Program Files (x86)\Intel\ComposerXE-2011\bin intel64
But I still got the "Access denied" message when ever I attempt to make compiles with Intel 64 command prompt. I run it also as Administrator but instead, it won't locate the *.cpp source files, even when placed along with the .bat files in the ComposerXE-2011 bin folder.

Google search don't help much either. Puzzling.
Remember to use the Shift-Right click to open a command window with the directory containing the cpp files? THEN:
call "C:\Program Filess (x86)\...\bin\iclvars.bat" intel64

If that still does not work and you get another Access Denied error even logged in as Admin, it could be some kind of restriction with your trial version of Intel's compiler.

Maybe something is being lost in translation here. You would NOT append those lines to PATH in environment variables. You would append this:

;C:\Program Files (x86)\Intel\ComposerXE-2011\bin

Then Shift-Right click the directory with your sources,
Then iclvars intel64 at the command prompt
Then icl /EHsc /O3 ... *.cpp
etc.
Thanks gaard, I followed the procedure but there's a new situation; after using the command : icl /03 /EHsc/MT *.cpp /link /NODEFAULTLIB:msvcrt.lib, I get an error message asking for a FNP_Act_Installer.dll. I Googled it and downloaded both 32 & 64-bit versions. I installed the 32-bit version in C:\Windows\System32 but I still get this error message.

I will try to find the path to place the 64-bit FNP_Act_Installer.
Attachments
ERROR.PNG

Prima
Posts: 328
Joined: Tue Dec 14, 2010 6:12 am

Re: Designing an analysis friendly Stockfish?

Post by Prima » Fri Feb 11, 2011 7:54 pm

gaard, the FNP_Act_Installer.dll problem is now fixed. It turns out the 64-bit FNP_Act_Installer was missing from the Intel64 command propmt directory. I downloaded the needed FNP_Act_Installer 64-bit and placed in .....Intel\CompserXE-2011\bin\Intel64 folder. Now it compiles with the O3 switch.

As always, thanks for your patience and the knowledge imparted to me. Thanks all.

fruity
Posts: 29
Joined: Wed Feb 02, 2011 12:52 am

Re: Designing an analysis friendly Stockfish?

Post by fruity » Fri Feb 11, 2011 8:01 pm

mcostalba wrote:
I try to confirm the result with 60000 10'' games now.
:idea: My electricity provider will be glad :idea:
Ok. Let's do electricity providers happy. I'm going to add in test queue this one:

Code: Select all

Subject: Use TT in PV also in qsearch()

Patch from Fruity:

http://www.open-chess.org/viewtopic.php?f=5&t=1042&start=160

Slightly reshuffled by me.
---

diff --git a/src/search.cpp b/src/search.cpp
--- a/src/search.cpp
+++ b/src/search.cpp
@@ -293,6 +293,20 @@ namespace {
   }
 
   template <NodeType PvNode>
+  inline bool ok_to_use_TT(const TTEntry* tte, Depth depth, Value alpha, Value beta, int ply) {
+
+    Value v = value_from_tt(tte->value(), ply);
+
+    return  (   tte->depth() >= depth
+             || v >= Max(value_mate_in(PLY_MAX), beta)
+             || v <= Min(value_mated_in(PLY_MAX), alpha))
+          &&
+            (PvNode ? tte->type() == VALUE_TYPE_EXACT
+                    : (   ((tte->type() & VALUE_TYPE_LOWER) && v >= beta)
+                       || ((tte->type() & VALUE_TYPE_UPPER) && v <= alpha)));
+  }
+
+  template <NodeType PvNode>
   Depth extension(const Position& pos, Move m, bool captureOrPromotion, bool moveIsCheck, bool singleEvasion, bool mateThreat, bool* dangerous);
 
   bool check_is_dangerous(Position &pos, Move move, Value futilityBase, Value beta, Value *bValue);
@@ -300,7 +314,6 @@ namespace {
   bool value_is_mate(Value value);
   Value value_to_tt(Value v, int ply);
   Value value_from_tt(Value v, int ply);
-  bool ok_to_use_TT(const TTEntry* tte, Depth depth, Value beta, int ply);
   bool connected_threat(const Position& pos, Move m, Move threat);
   Value refine_eval(const TTEntry* tte, Value defaultEval, int ply);
   void update_history(const Position& pos, Move move, Depth depth, Move movesSearched[], int moveCount);
@@ -991,14 +1004,10 @@ namespace {
     tte = TT.retrieve(posKey);
     ttMove = tte ? tte->move() : MOVE_NONE;
 
-    // At PV nodes, we don't use the TT for pruning, but only for move ordering.
-    // This is to avoid problems in the following areas:
-    //
-    // * Repetition draw detection
-    // * Fifty move rule detection
-    // * Searching for a mate
-    // * Printing of full PV line
-    if (!PvNode && tte && ok_to_use_TT(tte, depth, beta, ply))
+    // At PV nodes we check for exact scores, while at non-PV nodes we check for
+    // and return a fail high/low. Biggest advantage at probing at PV nodes is
+    // to have a smooth experience in analysis mode.
+    if (tte && ok_to_use_TT<PvNode>(tte, depth, alpha, beta, ply))
     {
         TT.refresh(tte);
         ss->bestMove = ttMove; // Can be MOVE_NONE
@@ -1443,7 +1452,7 @@ split_point_start: // At split points actual search starts from here
     tte = TT.retrieve(pos.get_key());
     ttMove = (tte ? tte->move() : MOVE_NONE);
 
-    if (!PvNode && tte && ok_to_use_TT(tte, ttDepth, beta, ply))
+    if (tte && ok_to_use_TT<PvNode>(tte, ttDepth, alpha, beta, ply))
     {
         ss->bestMove = ttMove; // Can be MOVE_NONE
         return value_from_tt(tte->value(), ply);
@@ -1849,22 +1858,6 @@ split_point_start: // At split points actual search starts from here
   }
 
 
-  // ok_to_use_TT() returns true if a transposition table score
-  // can be used at a given point in search.
-
-  bool ok_to_use_TT(const TTEntry* tte, Depth depth, Value beta, int ply) {
-
-    Value v = value_from_tt(tte->value(), ply);
-
-    return   (   tte->depth() >= depth
-              || v >= Max(value_mate_in(PLY_MAX), beta)
-              || v < Min(value_mated_in(PLY_MAX), beta))
-
-          && (   ((tte->type() & VALUE_TYPE_LOWER) && v >= beta)
-              || ((tte->type() & VALUE_TYPE_UPPER) && v < beta));
-  }
-
-
   // refine_eval() returns the transposition table score if
   // possible otherwise falls back on static position evaluation.
 
diff --git a/src/tt.cpp b/src/tt.cpp
--- a/src/tt.cpp
+++ b/src/tt.cpp
@@ -121,7 +121,7 @@ void TranspositionTable::store(const Key posKey, Value v, ValueType t, Depth d,
           continue;
 
       c1 = (replace->generation() == generation ?  2 : 0);
-      c2 = (tte->generation() == generation ? -2 : 0);
+      c2 = (tte->generation() == generation || tte->type() == VALUE_TYPE_EXACT ? -2 : 0);
       c3 = (tte->depth() < replace->depth() ?  1 : 0);
 
       if (c1 + c2 + c3 > 0)

BTW I have thought a bit about your result because was unexpected. It is true that leaf nodes are the most but PV leaf nodes are a real rarity and also in that case the advantage of returning from TT instead of performing the actual searching is minimal. But I have found a possible side effect that could be more important. At the beginning of the search we perform a qsearch<PvNode>() on the root position to have a startup scoring and so a startup ordering. It can happen that the startup ordering plays a role and in this case also your patch that uses TT hits in qsearch().
Your code is not exactly functionally equivalent with mine, because in PV case I accept all mate(d) values, not only those outside the alpha-beta window. Please have a look again.

Code: Select all

  template <NodeType PvNode>
  inline bool ok_to_use_TT(const TTEntry* tte, Depth depth, Value beta, int ply) {

    Value v = value_from_tt(tte->value(), ply);

    return
    PvNode ?    tte->type() == VALUE_TYPE_EXACT
             && (   tte->depth() >= depth
                 || v >= value_mate_in(PLY_MAX)
                 || v <= value_mated_in(PLY_MAX))

           :    (   tte->depth() >= depth
                 || v >= Max(value_mate_in(PLY_MAX), beta)
                 || v <= Min(value_mated_in(PLY_MAX), alpha))
             && (   ((tte->type() & VALUE_TYPE_LOWER) && v >= beta)
                 || ((tte->type() & VALUE_TYPE_UPPER) && v <= alpha));
  }
intermediate state: +2727 -2622 =6957 in favor of my proposal.

mcostalba
Posts: 91
Joined: Thu Jun 10, 2010 11:45 pm
Real Name: Marco Costalba

Re: Designing an analysis friendly Stockfish?

Post by mcostalba » Sat Feb 12, 2011 10:34 am

fruity wrote: Your code is not exactly functionally equivalent with mine, because in PV case I accept all mate(d) values, not only those outside the alpha-beta window. Please have a look again.
Yes I noticed, in case current patch does not work I will retest with your original version.

BTW after 3250 games at 20" TC we are completely even 513 - 518 - 2219

fruity
Posts: 29
Joined: Wed Feb 02, 2011 12:52 am

Re: Designing an analysis friendly Stockfish?

Post by fruity » Sat Feb 12, 2011 11:42 am

mcostalba wrote:
fruity wrote: Your code is not exactly functionally equivalent with mine, because in PV case I accept all mate(d) values, not only those outside the alpha-beta window. Please have a look again.
Yes I noticed, in case current patch does not work I will retest with your original version.

BTW after 3250 games at 20" TC we are completely even 513 - 518 - 2219
What do you test at 20''? Your most recently given code against the code which probes in search() but not in qsearch()?
How many threads per engine do you use?

Another intermediate result from my test at 10'' after 31,465 games: +6952 -6689 =17824 (+3 Elo)
I use 1 thread per engine and let play 6 games simultaneously (6 core cpu).

Jeremy Bernstein
Site Admin
Posts: 1226
Joined: Wed Jun 09, 2010 7:49 am
Real Name: Jeremy Bernstein
Location: Berlin, Germany
Contact:

Re: Designing an analysis friendly Stockfish?

Post by Jeremy Bernstein » Sat Feb 12, 2011 11:45 am

New builds for anyone who likes. It's essentially the MC + Peter C additions + Fruity code + GTB support. TBs now display the full main line (up to MAX_PLY, which means you'll get maximum 101 moves for the PV). This might be a good time to determine if smooth scaling does anything useful...

Enjoy!
jb
Attachments
Stockfish_201_PAMC_GTBg.7z
(516.32 KiB) Downloaded 182 times

mcostalba
Posts: 91
Joined: Thu Jun 10, 2010 11:45 pm
Real Name: Marco Costalba

Re: Designing an analysis friendly Stockfish?

Post by mcostalba » Sat Feb 12, 2011 6:29 pm

fruity wrote: What do you test at 20''? Your most recently given code against the code which probes in search() but not in qsearch()?
How many threads per engine do you use?

Another intermediate result from my test at 10'' after 31,465 games: +6952 -6689 =17824 (+3 Elo)
I use 1 thread per engine and let play 6 games simultaneously (6 core cpu).
For this test I use 20"+0.1 (to reduce noise due to time losses) 4 threads per engine (the full QUAD), I am testing _your_ most recently given code against the code which probes in search() but not in qsearch(), I have given up with mine given no measurable increase.

Test is started from not a long ago so after about 1800 games we are absolutely even 286 - 282 - 1210

fruity
Posts: 29
Joined: Wed Feb 02, 2011 12:52 am

Re: Designing an analysis friendly Stockfish?

Post by fruity » Sat Feb 12, 2011 7:36 pm

mcostalba wrote:
fruity wrote: What do you test at 20''? Your most recently given code against the code which probes in search() but not in qsearch()?
How many threads per engine do you use?

Another intermediate result from my test at 10'' after 31,465 games: +6952 -6689 =17824 (+3 Elo)
I use 1 thread per engine and let play 6 games simultaneously (6 core cpu).
For this test I use 20"+0.1 (to reduce noise due to time losses) 4 threads per engine (the full QUAD), I am testing _your_ most recently given code against the code which probes in search() but not in qsearch(), I have given up with mine given no measurable increase.

Test is started from not a long ago so after about 1800 games we are absolutely even 286 - 282 - 1210
+9071 -8774 =23509, +2 Elo after 41,354 games here. Might come down to what is better for analysis purposes. But let's burn the cores a little further ...

mcostalba
Posts: 91
Joined: Thu Jun 10, 2010 11:45 pm
Real Name: Marco Costalba

Re: Designing an analysis friendly Stockfish?

Post by mcostalba » Sun Feb 13, 2011 9:44 am

fruity wrote: +9071 -8774 =23509, +2 Elo after 41,354 games here. Might come down to what is better for analysis purposes. But let's burn the cores a little further ...
Ok, I stop now:

After 5244 games Mod- Orig: 819 - 807 - 3618 0 ELO (+- 3.8)

The interesting thing is that it seems to depend on TC going from 2" on a single core to 20" on 4 cores with about a 40X increase in search tree size result drops of about 4-5 ELO.

This makes me think that ultra fast games are good to spot big differences, but a 5 ELO feature is risky to be proved on super fast TC alone.

Post Reply