Compare commits

..

8 Commits

Author SHA1 Message Date
Marco Costalba 86c2d2fc3b Stockfish 1.7.1
Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-10 16:48:25 +01:00
Marco Costalba f9d3b48ad0 Introduce "Zugzwang detection" temporary hack for 1.7.1
Add an UCI option "Zugzwang detection" OFF by default that
enables correct detection of zugzwang.

This is just to let 1.7.1 be 100% compatible with 1.7 and
should be removed after release.

Verified 100% functional equivalent to 1.7

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-10 16:41:40 +01:00
Marco Costalba d720778b2b Revert HT detection
Fall back on 1.6.3 behaviour.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-10 11:35:30 +01:00
Marco Costalba e2880f9b8e Revert last patch
It fails in test position:

8/7P/8/8/K2b4/p7/1k6/1B6 b - -

Not clear why but we revert because it fixes the issue.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-10 11:16:55 +01:00
Marco Costalba 909e3adede Relax TT condition for zugzwang verified null values
In this case use a normal VALUE_TYPE_LOWER TT type instead of
VALUE_TYPE_NS_LO. This allow us to TT cut-off in a bit more nodes.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-10 10:48:08 +01:00
Marco Costalba 626b1f8c6a Avoid TT cutoffs at root of null zugzwang verification
This patch fixes an issue with zugzwang well explained by Tord:

"Assume that a zugzwang position occurs at iteration N,
at a search depth d, with d < 6*OnePly. The null move search
fails high, and no verification search is done, because the
depth is too small. The position gets stored in the transposition
table with a good score and a depth of d.

Now, consider what happens when the same position occurs at iteration
N+1, this time with a depth of d+OnePly (i.e. one ply deeper than at
the previous iteration). Once again, the null move search fails
high. The point is that the verification search will also fail high,
because of an instant transposition table cutoff caused by the value
stored in the TT during the previous iteration."

With this patch we simply do not allow TT cutoffs at the root node
of a null move verification search if the TT value was found by a
null search.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-10 10:35:29 +01:00
Marco Costalba 06a350f1ae Use a flag in TT to track null search values
Add VALUE_TYPE_NS_LO to enum ValueType and use it when
saving in TT a value from a null search.

Currently no action is performed, the next patch will enable
the new type.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-10 10:07:53 +01:00
Marco Costalba a9e9746495 Fix a warning under HP-UX ANSI C++
Reported warning is:

warning #2514-D: pointless comparison of unsigned
                 integer with a negative constant

Spotted by Richard Lloyd.

No functional change.

Signed-off-by: Marco Costalba <mcostalba@gmail.com>
2010-04-09 07:54:00 +01:00
6 changed files with 41 additions and 75 deletions
+2 -1
View File
@@ -27,7 +27,8 @@
enum Depth { enum Depth {
DEPTH_ZERO = 0, DEPTH_ZERO = 0,
DEPTH_MAX = 200 // 100 * OnePly; DEPTH_MAX = 200, // 100 * OnePly;
DEPTH_ENSURE_SIGNED = -1
}; };
+10 -56
View File
@@ -41,20 +41,20 @@
#include <cassert> #include <cassert>
#include <cstdio> #include <cstdio>
#include <cstring>
#include <iomanip> #include <iomanip>
#include <iostream> #include <iostream>
#include <sstream> #include <sstream>
#include "bitcount.h" #include "bitcount.h"
#include "misc.h" #include "misc.h"
#include "thread.h"
using namespace std; using namespace std;
/// Version number. If this is left empty, the current date (in the format /// Version number. If this is left empty, the current date (in the format
/// YYMMDD) is used as a version number. /// YYMMDD) is used as a version number.
static const string EngineVersion = "1.7"; static const string EngineVersion = "1.7.1";
static const string AppName = "Stockfish"; static const string AppName = "Stockfish";
static const string AppTag = ""; static const string AppTag = "";
@@ -183,85 +183,39 @@ int get_system_time() {
} }
/// builtin_cpu_count() tries to detect the number of CPU cores, if /// cpu_count() tries to detect the number of CPU cores.
/// hyper-threading is enabled this is the number of logical processors.
#if !defined(_MSC_VER) #if !defined(_MSC_VER)
# if defined(_SC_NPROCESSORS_ONLN) # if defined(_SC_NPROCESSORS_ONLN)
static int builtin_cpu_count() { int cpu_count() {
return Min(sysconf(_SC_NPROCESSORS_ONLN), 8); return Min(sysconf(_SC_NPROCESSORS_ONLN), MAX_THREADS);
} }
# elif defined(__hpux) # elif defined(__hpux)
static int builtin_cpu_count() { int cpu_count() {
struct pst_dynamic psd; struct pst_dynamic psd;
if (pstat_getdynamic(&psd, sizeof(psd), (size_t)1, 0) == -1) if (pstat_getdynamic(&psd, sizeof(psd), (size_t)1, 0) == -1)
return 1; return 1;
return Min(psd.psd_proc_cnt, 8); return Min(psd.psd_proc_cnt, MAX_THREADS);
} }
# else # else
static int builtin_cpu_count() { int cpu_count() {
return 1; return 1;
} }
# endif # endif
#else #else
static int builtin_cpu_count() { int cpu_count() {
SYSTEM_INFO s; SYSTEM_INFO s;
GetSystemInfo(&s); GetSystemInfo(&s);
return Min(s.dwNumberOfProcessors, 8); return Min(s.dwNumberOfProcessors, MAX_THREADS);
} }
#endif #endif
/// HT_enabled() returns true if hyper-threading is enabled on current machine
static bool HT_enabled() {
char CPUString[0x20];
int CPUInfo[4] = {-1};
int nIds, nLogicalCPU, nCores;
// Detect CPU producer
__cpuid(CPUInfo, 0);
nIds = CPUInfo[0];
memset(CPUString, 0, sizeof(CPUString));
memcpy(&CPUString[0], &CPUInfo[1], sizeof(int));
memcpy(&CPUString[4], &CPUInfo[3], sizeof(int));
memcpy(&CPUString[8], &CPUInfo[2], sizeof(int));
// Not an Intel CPU or CPUID.4 not supported
if (strcmp(CPUString, "GenuineIntel") || nIds < 4)
return false;
// Detect if HT Technology is supported
__cpuid(CPUInfo, 1);
if (!((CPUInfo[3] >> 28) & 1))
return false;
nLogicalCPU = (CPUInfo[1] >> 16) & 0xFF;
// Detect number of cores
__cpuid(CPUInfo, 4);
nCores = 1 + ((CPUInfo[0] >> 26) & 0x3F);
return nLogicalCPU > nCores;
}
/// cpu_count() tries to detect the number of physical CPU cores taking
/// in account hyper-threading.
int cpu_count() {
return HT_enabled() ? builtin_cpu_count() / 2 : builtin_cpu_count();
}
/* /*
From Beowulf, from Olithink From Beowulf, from Olithink
*/ */
+15 -10
View File
@@ -257,7 +257,7 @@ namespace {
int SearchStartTime, MaxNodes, MaxDepth, MaxSearchTime; int SearchStartTime, MaxNodes, MaxDepth, MaxSearchTime;
int AbsoluteMaxSearchTime, ExtraSearchTime, ExactMaxTime; int AbsoluteMaxSearchTime, ExtraSearchTime, ExactMaxTime;
bool UseTimeManagement, InfiniteSearch, PonderSearch, StopOnPonderhit; bool UseTimeManagement, InfiniteSearch, PonderSearch, StopOnPonderhit;
bool FirstRootMove, AbortSearch, Quit, AspirationFailLow; bool FirstRootMove, AbortSearch, Quit, AspirationFailLow, ZugDetection;
// Log file // Log file
bool UseLogFile; bool UseLogFile;
@@ -294,7 +294,7 @@ namespace {
Depth extension(const Position&, Move, bool, bool, bool, bool, bool, bool*); Depth extension(const Position&, Move, bool, bool, bool, bool, bool, bool*);
bool ok_to_do_nullmove(const Position& pos); bool ok_to_do_nullmove(const Position& pos);
bool ok_to_prune(const Position& pos, Move m, Move threat); bool ok_to_prune(const Position& pos, Move m, Move threat);
bool ok_to_use_TT(const TTEntry* tte, Depth depth, Value beta, int ply); bool ok_to_use_TT(const TTEntry* tte, Depth depth, Value beta, int ply, bool allowNullmove);
Value refine_eval(const TTEntry* tte, Value defaultEval, int ply); Value refine_eval(const TTEntry* tte, Value defaultEval, int ply);
void update_history(const Position& pos, Move move, Depth depth, Move movesSearched[], int moveCount); void update_history(const Position& pos, Move move, Depth depth, Move movesSearched[], int moveCount);
void update_killers(Move m, SearchStack& ss); void update_killers(Move m, SearchStack& ss);
@@ -425,6 +425,7 @@ bool think(const Position& pos, bool infinite, bool ponder, int side_to_move,
MultiPV = get_option_value_int("MultiPV"); MultiPV = get_option_value_int("MultiPV");
Chess960 = get_option_value_bool("UCI_Chess960"); Chess960 = get_option_value_bool("UCI_Chess960");
UseLogFile = get_option_value_bool("Use Search Log"); UseLogFile = get_option_value_bool("Use Search Log");
ZugDetection = get_option_value_bool("Zugzwang detection"); // To be removed after 1.7.1
if (UseLogFile) if (UseLogFile)
LogFile.open(get_option_value_string("Search Log Filename").c_str(), std::ios::out | std::ios::app); LogFile.open(get_option_value_string("Search Log Filename").c_str(), std::ios::out | std::ios::app);
@@ -1299,7 +1300,7 @@ namespace {
tte = TT.retrieve(posKey); tte = TT.retrieve(posKey);
ttMove = (tte ? tte->move() : MOVE_NONE); ttMove = (tte ? tte->move() : MOVE_NONE);
if (tte && ok_to_use_TT(tte, depth, beta, ply)) if (tte && ok_to_use_TT(tte, depth, beta, ply, allowNullmove))
{ {
ss[ply].currentMove = ttMove; // Can be MOVE_NONE ss[ply].currentMove = ttMove; // Can be MOVE_NONE
return value_from_tt(tte->value(), ply); return value_from_tt(tte->value(), ply);
@@ -1388,7 +1389,7 @@ namespace {
{ {
assert(value_to_tt(nullValue, ply) == nullValue); assert(value_to_tt(nullValue, ply) == nullValue);
TT.store(posKey, nullValue, VALUE_TYPE_LOWER, depth, MOVE_NONE); TT.store(posKey, nullValue, VALUE_TYPE_NS_LO, depth, MOVE_NONE);
return nullValue; return nullValue;
} }
} else { } else {
@@ -1625,7 +1626,7 @@ namespace {
tte = TT.retrieve(pos.get_key()); tte = TT.retrieve(pos.get_key());
ttMove = (tte ? tte->move() : MOVE_NONE); ttMove = (tte ? tte->move() : MOVE_NONE);
if (!pvNode && tte && ok_to_use_TT(tte, depth, beta, ply)) if (!pvNode && tte && ok_to_use_TT(tte, depth, beta, ply, true))
{ {
assert(tte->type() != VALUE_TYPE_EVAL); assert(tte->type() != VALUE_TYPE_EVAL);
@@ -1666,7 +1667,7 @@ namespace {
alpha = bestValue; alpha = bestValue;
// If we are near beta then try to get a cutoff pushing checks a bit further // If we are near beta then try to get a cutoff pushing checks a bit further
bool deepChecks = depth == -OnePly && staticValue >= beta - PawnValueMidgame / 8; bool deepChecks = (depth == -OnePly && staticValue >= beta - PawnValueMidgame / 8);
// Initialize a MovePicker object for the current position, and prepare // Initialize a MovePicker object for the current position, and prepare
// to search the moves. Because the depth is <= 0 here, only captures, // to search the moves. Because the depth is <= 0 here, only captures,
@@ -2306,14 +2307,18 @@ namespace {
} }
// ok_to_use_TT() returns true if a transposition table score // ok_to_use_TT() returns true if a transposition table score can be used at a
// can be used at a given point in search. // given point in search. To avoid zugzwang issues TT cutoffs at the root node
// of a null move verification search are not allowed if the TT value was found
// by a null search, this is implemented testing allowNullmove and TT entry type.
bool ok_to_use_TT(const TTEntry* tte, Depth depth, Value beta, int ply) { bool ok_to_use_TT(const TTEntry* tte, Depth depth, Value beta, int ply, bool allowNullmove) {
Value v = value_from_tt(tte->value(), ply); Value v = value_from_tt(tte->value(), ply);
return ( tte->depth() >= depth return (allowNullmove || !(tte->type() & VALUE_TYPE_NULL) || !ZugDetection)
&& ( tte->depth() >= depth
|| v >= Max(value_mate_in(PLY_MAX), beta) || v >= Max(value_mate_in(PLY_MAX), beta)
|| v < Min(value_mated_in(PLY_MAX), beta)) || v < Min(value_mated_in(PLY_MAX), beta))
+4 -4
View File
@@ -46,8 +46,8 @@
/// the 32 bits of the data field are so defined /// the 32 bits of the data field are so defined
/// ///
/// bit 0-16: move /// bit 0-16: move
/// bit 17-19: not used /// bit 17-18: not used
/// bit 20-22: value type /// bit 19-22: value type
/// bit 23-31: generation /// bit 23-31: generation
class TTEntry { class TTEntry {
@@ -55,14 +55,14 @@ class TTEntry {
public: public:
TTEntry() {} TTEntry() {}
TTEntry(uint32_t k, Value v, ValueType t, Depth d, Move m, int generation) TTEntry(uint32_t k, Value v, ValueType t, Depth d, Move m, int generation)
: key_ (k), data((m & 0x1FFFF) | (t << 20) | (generation << 23)), : key_ (k), data((m & 0x1FFFF) | (t << 19) | (generation << 23)),
value_(int16_t(v)), depth_(int16_t(d)) {} value_(int16_t(v)), depth_(int16_t(d)) {}
uint32_t key() const { return key_; } uint32_t key() const { return key_; }
Depth depth() const { return Depth(depth_); } Depth depth() const { return Depth(depth_); }
Move move() const { return Move(data & 0x1FFFF); } Move move() const { return Move(data & 0x1FFFF); }
Value value() const { return Value(value_); } Value value() const { return Value(value_); }
ValueType type() const { return ValueType((data >> 20) & 7); } ValueType type() const { return ValueType((data >> 19) & 0xF); }
int generation() const { return (data >> 23); } int generation() const { return (data >> 23); }
private: private:
+3
View File
@@ -113,6 +113,9 @@ namespace {
o["UCI_Chess960"] = Option(false); o["UCI_Chess960"] = Option(false);
o["UCI_AnalyseMode"] = Option(false); o["UCI_AnalyseMode"] = Option(false);
// Temporary hack for 1.7.1 to be removed in next release
o["Zugzwang detection"] = Option(false);
// Any option should know its name so to be easily printed // Any option should know its name so to be easily printed
for (Options::iterator it = o.begin(); it != o.end(); ++it) for (Options::iterator it = o.begin(); it != o.end(); ++it)
it->second.name = it->first; it->second.name = it->first;
+7 -4
View File
@@ -33,13 +33,16 @@
//// ////
enum ValueType { enum ValueType {
VALUE_TYPE_NONE = 0, VALUE_TYPE_NONE = 0,
VALUE_TYPE_UPPER = 1, // Upper bound VALUE_TYPE_UPPER = 1, // Upper bound
VALUE_TYPE_LOWER = 2, // Lower bound VALUE_TYPE_LOWER = 2, // Lower bound
VALUE_TYPE_EXACT = 3, // Exact score VALUE_TYPE_EXACT = 3, // Exact score
VALUE_TYPE_EVAL = 4, // Evaluation cache VALUE_TYPE_EVAL = 4, // Static evaluation value
VALUE_TYPE_EV_UP = 5, // Evaluation cache for upper bound VALUE_TYPE_NULL = 8, // Null search value
VALUE_TYPE_EV_LO = 6 // Evaluation cache for lower bound
VALUE_TYPE_EV_UP = VALUE_TYPE_EVAL | VALUE_TYPE_UPPER,
VALUE_TYPE_EV_LO = VALUE_TYPE_EVAL | VALUE_TYPE_LOWER,
VALUE_TYPE_NS_LO = VALUE_TYPE_NULL | VALUE_TYPE_LOWER,
}; };