From: Marco Costalba Date: Fri, 16 Apr 2010 05:19:33 +0000 (+0100) Subject: Revert saving of null search value in TT X-Git-Url: https://git.sesse.net/?p=stockfish;a=commitdiff_plain;h=65c2715d9a49c8a6119bb1e03fcd7f54cfa1d4b8;ds=sidebyside Revert saving of null search value in TT Revert all the patches that introduced the change and more or less fixed the zugzwang issue. There is a gain against last current version and we can remove a lot of code. After 979 games at 1+0 on my QUAD Mod vs Orig +152 =688 -139 +5 ELO Signed-off-by: Marco Costalba --- diff --git a/src/search.cpp b/src/search.cpp index 4c7e1e46..5cca911b 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -104,13 +104,6 @@ namespace { }; - // FIXME: document me - - enum NullStatus { - ALLOW_NULLMOVE, - FORBID_NULLMOVE, - VERIFY_NULLMOVE - }; // RootMove struct is used for moves at the root at the tree. For each // root move, we store a score, a node count, and a PV (really a refutation @@ -288,7 +281,7 @@ namespace { Value id_loop(const Position& pos, Move searchMoves[]); Value root_search(Position& pos, SearchStack ss[], RootMoveList& rml, Value* alphaPtr, Value* betaPtr); Value search_pv(Position& pos, SearchStack ss[], Value alpha, Value beta, Depth depth, int ply, int threadID); - Value search(Position& pos, SearchStack ss[], Value beta, Depth depth, int ply, NullStatus nullStatus, int threadID, Move excludedMove = MOVE_NONE); + Value search(Position& pos, SearchStack ss[], Value beta, Depth depth, int ply, bool allowNullmove, int threadID, Move excludedMove = MOVE_NONE); Value qsearch(Position& pos, SearchStack ss[], Value alpha, Value beta, Depth depth, int ply, int threadID); void sp_search(SplitPoint* sp, int threadID); void sp_search_pv(SplitPoint* sp, int threadID); @@ -301,7 +294,7 @@ namespace { Depth extension(const Position&, Move, bool, bool, bool, bool, bool, bool*); bool ok_to_do_nullmove(const Position& pos); 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 allowNullmove); + bool ok_to_use_TT(const TTEntry* tte, Depth depth, Value beta, 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_killers(Move m, SearchStack& ss); @@ -893,7 +886,7 @@ namespace { if (ss[0].reduction) { // Reduced depth non-pv search using alpha as upperbound - value = -search(pos, ss, -alpha, newDepth-ss[0].reduction, 1, ALLOW_NULLMOVE, 0); + value = -search(pos, ss, -alpha, newDepth-ss[0].reduction, 1, true, 0); doFullDepthSearch = (value > alpha); } } @@ -903,7 +896,7 @@ namespace { { // Full depth non-pv search using alpha as upperbound ss[0].reduction = Depth(0); - value = -search(pos, ss, -alpha, newDepth, 1, ALLOW_NULLMOVE, 0); + value = -search(pos, ss, -alpha, newDepth, 1, true, 0); // If we are above alpha then research at same depth but as PV // to get a correct score or eventually a fail high above beta. @@ -1138,7 +1131,7 @@ namespace { if (abs(ttValue) < VALUE_KNOWN_WIN) { - Value excValue = search(pos, ss, ttValue - SingularExtensionMargin, depth / 2, ply, FORBID_NULLMOVE, threadID, move); + Value excValue = search(pos, ss, ttValue - SingularExtensionMargin, depth / 2, ply, false, threadID, move); if (excValue < ttValue - SingularExtensionMargin) ext = OnePly; @@ -1174,7 +1167,7 @@ namespace { ss[ply].reduction = pv_reduction(depth, moveCount); if (ss[ply].reduction) { - value = -search(pos, ss, -alpha, newDepth-ss[ply].reduction, ply+1, ALLOW_NULLMOVE, threadID); + value = -search(pos, ss, -alpha, newDepth-ss[ply].reduction, ply+1, true, threadID); doFullDepthSearch = (value > alpha); } } @@ -1183,7 +1176,7 @@ namespace { if (doFullDepthSearch) { ss[ply].reduction = Depth(0); - value = -search(pos, ss, -alpha, newDepth, ply+1, ALLOW_NULLMOVE, threadID); + value = -search(pos, ss, -alpha, newDepth, ply+1, true, threadID); // Step extra. pv search (only in PV nodes) if (value > alpha && value < beta) @@ -1258,7 +1251,7 @@ namespace { // search() is the search function for zero-width nodes. Value search(Position& pos, SearchStack ss[], Value beta, Depth depth, - int ply, NullStatus nullStatus, int threadID, Move excludedMove) { + int ply, bool allowNullmove, int threadID, Move excludedMove) { assert(beta >= -VALUE_INFINITE && beta <= VALUE_INFINITE); assert(ply >= 0 && ply < PLY_MAX); @@ -1306,7 +1299,7 @@ namespace { tte = TT.retrieve(posKey); ttMove = (tte ? tte->move() : MOVE_NONE); - if (tte && ok_to_use_TT(tte, depth, beta, ply, nullStatus != VERIFY_NULLMOVE)) + if (tte && ok_to_use_TT(tte, depth, beta, ply)) { ss[ply].currentMove = ttMove; // Can be MOVE_NONE return value_from_tt(tte->value(), ply); @@ -1346,7 +1339,7 @@ namespace { // Step 7. Static null move pruning // We're betting that the opponent doesn't have a move that will reduce // the score by more than futility_margin(depth) if we do a null move. - if ( nullStatus == ALLOW_NULLMOVE + if ( allowNullmove && depth < RazorDepth && !isCheck && !value_is_mate(beta) @@ -1358,7 +1351,7 @@ namespace { // When we jump directly to qsearch() we do a null move only if static value is // at least beta. Otherwise we do a null move if static value is not more than // NullMoveMargin under beta. - if ( nullStatus == ALLOW_NULLMOVE + if ( allowNullmove && depth > OnePly && !isCheck && !value_is_mate(beta) @@ -1376,7 +1369,7 @@ namespace { pos.do_null_move(st); - nullValue = -search(pos, ss, -(beta-1), depth-R*OnePly, ply+1, FORBID_NULLMOVE, threadID); + nullValue = -search(pos, ss, -(beta-1), depth-R*OnePly, ply+1, false, threadID); pos.undo_null_move(); @@ -1386,20 +1379,13 @@ namespace { if (nullValue >= value_mate_in(PLY_MAX)) nullValue = beta; - // Do zugzwang verification search for high depths, don't store in TT - // if search was stopped. - if ( ( depth < 6 * OnePly - || search(pos, ss, beta, depth-5*OnePly, ply, VERIFY_NULLMOVE, threadID) >= beta) - && !AbortSearch - && !TM.thread_should_stop(threadID)) - { - assert(value_to_tt(nullValue, ply) == nullValue); - - if (!tte) - TT.store(posKey, nullValue, VALUE_TYPE_NS_LO, depth, MOVE_NONE); + if (depth < 6 * OnePly) + return nullValue; + // Do zugzwang verification search + Value v = search(pos, ss, beta, depth-5*OnePly, ply, false, threadID); + if (v >= beta) return nullValue; - } } else { // The null move failed low, which means that we may be faced with // some kind of threat. If the previous move was reduced, check if @@ -1424,7 +1410,7 @@ namespace { && !isCheck && ss[ply].eval >= beta - IIDMargin) { - search(pos, ss, beta, depth/2, ply, FORBID_NULLMOVE, threadID); + search(pos, ss, beta, depth/2, ply, false, threadID); ttMove = ss[ply].pv[ply]; tte = TT.retrieve(posKey); } @@ -1466,7 +1452,7 @@ namespace { if (abs(ttValue) < VALUE_KNOWN_WIN) { - Value excValue = search(pos, ss, ttValue - SingularExtensionMargin, depth / 2, ply, FORBID_NULLMOVE, threadID, move); + Value excValue = search(pos, ss, ttValue - SingularExtensionMargin, depth / 2, ply, false, threadID, move); if (excValue < ttValue - SingularExtensionMargin) ext = OnePly; @@ -1520,7 +1506,7 @@ namespace { ss[ply].reduction = nonpv_reduction(depth, moveCount); if (ss[ply].reduction) { - value = -search(pos, ss, -(beta-1), newDepth-ss[ply].reduction, ply+1, ALLOW_NULLMOVE, threadID); + value = -search(pos, ss, -(beta-1), newDepth-ss[ply].reduction, ply+1, true, threadID); doFullDepthSearch = (value >= beta); } } @@ -1529,7 +1515,7 @@ namespace { if (doFullDepthSearch) { ss[ply].reduction = Depth(0); - value = -search(pos, ss, -(beta-1), newDepth, ply+1, ALLOW_NULLMOVE, threadID); + value = -search(pos, ss, -(beta-1), newDepth, ply+1, true, threadID); } // Step 16. Undo move @@ -1634,7 +1620,7 @@ namespace { tte = TT.retrieve(pos.get_key()); ttMove = (tte ? tte->move() : MOVE_NONE); - if (!pvNode && tte && ok_to_use_TT(tte, depth, beta, ply, true)) + if (!pvNode && tte && ok_to_use_TT(tte, depth, beta, ply)) { assert(tte->type() != VALUE_TYPE_EVAL); @@ -1879,7 +1865,7 @@ namespace { ss[sp->ply].reduction = nonpv_reduction(sp->depth, moveCount); if (ss[sp->ply].reduction) { - value = -search(pos, ss, -(sp->beta-1), newDepth-ss[sp->ply].reduction, sp->ply+1, ALLOW_NULLMOVE, threadID); + value = -search(pos, ss, -(sp->beta-1), newDepth-ss[sp->ply].reduction, sp->ply+1, true, threadID); doFullDepthSearch = (value >= sp->beta && !TM.thread_should_stop(threadID)); } } @@ -1888,7 +1874,7 @@ namespace { if (doFullDepthSearch) { ss[sp->ply].reduction = Depth(0); - value = -search(pos, ss, -(sp->beta - 1), newDepth, sp->ply+1, ALLOW_NULLMOVE, threadID); + value = -search(pos, ss, -(sp->beta - 1), newDepth, sp->ply+1, true, threadID); } // Step 16. Undo move @@ -1985,7 +1971,7 @@ namespace { if (ss[sp->ply].reduction) { Value localAlpha = sp->alpha; - value = -search(pos, ss, -localAlpha, newDepth-ss[sp->ply].reduction, sp->ply+1, ALLOW_NULLMOVE, threadID); + value = -search(pos, ss, -localAlpha, newDepth-ss[sp->ply].reduction, sp->ply+1, true, threadID); doFullDepthSearch = (value > localAlpha && !TM.thread_should_stop(threadID)); } } @@ -1995,7 +1981,7 @@ namespace { { Value localAlpha = sp->alpha; ss[sp->ply].reduction = Depth(0); - value = -search(pos, ss, -localAlpha, newDepth, sp->ply+1, ALLOW_NULLMOVE, threadID); + value = -search(pos, ss, -localAlpha, newDepth, sp->ply+1, true, threadID); if (value > localAlpha && value < sp->beta && !TM.thread_should_stop(threadID)) { @@ -2315,18 +2301,14 @@ namespace { } - // ok_to_use_TT() returns true if a transposition table score can be used at a - // 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. + // 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, bool allowNullmove) { + bool ok_to_use_TT(const TTEntry* tte, Depth depth, Value beta, int ply) { Value v = value_from_tt(tte->value(), ply); - return (allowNullmove || !(tte->type() & VALUE_TYPE_NULL)) - - && ( tte->depth() >= depth + return ( tte->depth() >= depth || v >= Max(value_mate_in(PLY_MAX), beta) || v < Min(value_mated_in(PLY_MAX), beta)) diff --git a/src/tt.h b/src/tt.h index 021019be..272e752b 100644 --- a/src/tt.h +++ b/src/tt.h @@ -46,8 +46,8 @@ /// the 32 bits of the data field are so defined /// /// bit 0-16: move -/// bit 17-18: not used -/// bit 19-22: value type +/// bit 17-19: not used +/// bit 20-22: value type /// bit 23-31: generation class TTEntry { @@ -55,14 +55,14 @@ class TTEntry { public: TTEntry() {} TTEntry(uint32_t k, Value v, ValueType t, Depth d, Move m, int generation) - : key_ (k), data((m & 0x1FFFF) | (t << 19) | (generation << 23)), + : key_ (k), data((m & 0x1FFFF) | (t << 20) | (generation << 23)), value_(int16_t(v)), depth_(int16_t(d)) {} uint32_t key() const { return key_; } Depth depth() const { return Depth(depth_); } Move move() const { return Move(data & 0x1FFFF); } Value value() const { return Value(value_); } - ValueType type() const { return ValueType((data >> 19) & 0xF); } + ValueType type() const { return ValueType((data >> 20) & 7); } int generation() const { return (data >> 23); } private: diff --git a/src/value.h b/src/value.h index dd2c3941..ed2bbb24 100644 --- a/src/value.h +++ b/src/value.h @@ -33,16 +33,14 @@ //// enum ValueType { - VALUE_TYPE_NONE = 0, + VALUE_TYPE_NONE = 0, VALUE_TYPE_UPPER = 1, // Upper bound VALUE_TYPE_LOWER = 2, // Lower bound - VALUE_TYPE_EXACT = 3, // Exact score VALUE_TYPE_EVAL = 4, // Static evaluation value - VALUE_TYPE_NULL = 8, // Null search value - 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 + VALUE_TYPE_EXACT = VALUE_TYPE_UPPER | VALUE_TYPE_LOWER, + VALUE_TYPE_EV_UP = VALUE_TYPE_EVAL | VALUE_TYPE_UPPER, + VALUE_TYPE_EV_LO = VALUE_TYPE_EVAL | VALUE_TYPE_LOWER };