From 717d6c5ed503543c66eb7a2c10e8a97c88d99862 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Fri, 29 Oct 2021 17:45:09 +0200 Subject: [PATCH 001/105] Widen the aspiration window for larger evals passed STC LLR: 2.93 (-2.94,2.94) <-0.50,2.50> Total: 36840 W: 9359 L: 9134 D: 18347 Ptnml(0-2): 111, 4130, 9722, 4337, 120 https://tests.stockfishchess.org/tests/view/617c601301c6d0988731d10a passed LTC LLR: 2.98 (-2.94,2.94) <0.50,3.50> Total: 64824 W: 16377 L: 16043 D: 32404 Ptnml(0-2): 27, 6712, 18618, 7010, 45 https://tests.stockfishchess.org/tests/view/617c720d01c6d0988731d114 closes https://github.com/official-stockfish/Stockfish/pull/3768 Bench: 7683058 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 36329f8f..14de2377 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -380,7 +380,7 @@ void Thread::search() { if (rootDepth >= 4) { Value prev = rootMoves[pvIdx].previousScore; - delta = Value(17); + delta = Value(17) + int(prev) * prev / 16384; alpha = std::max(prev - delta,-VALUE_INFINITE); beta = std::min(prev + delta, VALUE_INFINITE); From a8330d5c3bfeb4c9d5c55083223792e0989bb9c6 Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Sun, 31 Oct 2021 12:09:40 +0100 Subject: [PATCH 002/105] Do more deeper LMR searches. At expected cut nodes allow at least one ply deeper LMR search for the first seventh moves. STC: LLR: 2.93 (-2.94,2.94) <-0.50,2.50> Total: 42880 W: 10964 L: 10738 D: 21178 Ptnml(0-2): 105, 4565, 11883, 4773, 114 https://tests.stockfishchess.org/tests/view/6179abd7a9b1d8fbcc4ee6f4 LTC: LLR: 2.93 (-2.94,2.94) <0.50,3.50> Total: 66872 W: 16930 L: 16603 D: 33339 Ptnml(0-2): 36, 6509, 20024, 6826, 41 https://tests.stockfishchess.org/tests/view/617a30fb2fbca9ca65972b5e closes https://github.com/official-stockfish/Stockfish/pull/3770 Bench: 6295536 --- src/search.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 14de2377..c7c8e782 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1209,10 +1209,11 @@ moves_loop: // When in check, search starts here // In general we want to cap the LMR depth search at newDepth. But if reductions // are really negative and movecount is low, we allow this move to be searched // deeper than the first move (this may lead to hidden double extensions). - int deeper = r >= -1 ? 0 - : moveCount <= 5 ? 2 - : PvNode && depth > 6 ? 1 - : 0; + int deeper = r >= -1 ? 0 + : moveCount <= 5 ? 2 + : PvNode && depth > 6 ? 1 + : cutNode && moveCount <= 7 ? 1 + : 0; Depth d = std::clamp(newDepth - r, 1, newDepth + deeper); From 0e89d6e7546d26a19a108d047b489d9ba6f7970c Mon Sep 17 00:00:00 2001 From: Michel Van den Bergh Date: Sun, 31 Oct 2021 19:35:30 +0100 Subject: [PATCH 003/105] Do not output to stderr during the build. To help with debugging, the worker sends the output of stderr (suitable truncated) to the action log on the server, in case a build fails. For this to work it is important that there is no spurious output to stderr. closes https://github.com/official-stockfish/Stockfish/pull/3773 No functional change --- src/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile b/src/Makefile index fea597e7..5c52661b 100644 --- a/src/Makefile +++ b/src/Makefile @@ -751,7 +751,7 @@ profile-build: net config-sanity objclean profileclean $(MAKE) ARCH=$(ARCH) COMP=$(COMP) $(profile_make) @echo "" @echo "Step 2/4. Running benchmark for pgo-build ..." - $(PGOBENCH) > /dev/null + $(PGOBENCH) 2>&1 | tail -n 4 @echo "" @echo "Step 3/4. Building optimized executable ..." $(MAKE) ARCH=$(ARCH) COMP=$(COMP) objclean From ef4822aa8d5945d490acca674eb1db8c3c38e9d5 Mon Sep 17 00:00:00 2001 From: xefoci7612 Date: Sun, 10 Oct 2021 14:03:51 +0200 Subject: [PATCH 004/105] Simplify Skill implementation Currently we handle the UCI_Elo with a double randomization. This seems not necessary and a bit involuted. This patch removes the first randomization and unifies the 2 cases. closes https://github.com/official-stockfish/Stockfish/pull/3769 No functional change. --- AUTHORS | 1 + src/search.cpp | 41 +++++++++++++++++++---------------------- 2 files changed, 20 insertions(+), 22 deletions(-) diff --git a/AUTHORS b/AUTHORS index 56725e98..35ccdaf5 100644 --- a/AUTHORS +++ b/AUTHORS @@ -194,6 +194,7 @@ tttak Unai Corzo (unaiic) Uri Blass (uriblass) Vince Negri (cuddlestmonkey) +xefoci7612 zz4032 diff --git a/src/search.cpp b/src/search.cpp index c7c8e782..075be835 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -112,14 +112,22 @@ namespace { return thisThread->state; } - // Skill structure is used to implement strength limit + // Skill structure is used to implement strength limit. If we have an uci_elo then + // we convert it to a suitable fractional skill level using anchoring to CCRL Elo + // (goldfish 1.13 = 2000) and a fit through Ordo derived Elo for match (TC 60+0.6) + // results spanning a wide range of k values. struct Skill { - explicit Skill(int l) : level(l) {} - bool enabled() const { return level < 20; } - bool time_to_pick(Depth depth) const { return depth == 1 + level; } + Skill(int skill_level, int uci_elo) { + if (uci_elo) + level = std::clamp(std::pow((uci_elo - 1346.6) / 143.4, 1 / 0.806), 0.0, 20.0); + else + level = double(skill_level); + } + bool enabled() const { return level < 20.0; } + bool time_to_pick(Depth depth) const { return depth == 1 + int(level); } Move pick_best(size_t multiPV); - int level; + double level; Move best = MOVE_NONE; }; @@ -243,10 +251,11 @@ void MainThread::search() { Time.availableNodes += Limits.inc[us] - Threads.nodes_searched(); Thread* bestThread = this; + Skill skill = Skill(Options["Skill Level"], Options["UCI_LimitStrength"] ? int(Options["UCI_Elo"]) : 0); if ( int(Options["MultiPV"]) == 1 && !Limits.depth - && !(Skill(Options["Skill Level"]).enabled() || int(Options["UCI_LimitStrength"])) + && !skill.enabled() && rootMoves[0].pv[0] != MOVE_NONE) bestThread = Threads.get_best_thread(); @@ -311,19 +320,7 @@ void Thread::search() { std::fill(&lowPlyHistory[MAX_LPH - 2][0], &lowPlyHistory.back().back() + 1, 0); size_t multiPV = size_t(Options["MultiPV"]); - - // Pick integer skill levels, but non-deterministically round up or down - // such that the average integer skill corresponds to the input floating point one. - // UCI_Elo is converted to a suitable fractional skill level, using anchoring - // to CCRL Elo (goldfish 1.13 = 2000) and a fit through Ordo derived Elo - // for match (TC 60+0.6) results spanning a wide range of k values. - PRNG rng(now()); - double floatLevel = Options["UCI_LimitStrength"] ? - std::clamp(std::pow((Options["UCI_Elo"] - 1346.6) / 143.4, 1 / 0.806), 0.0, 20.0) : - double(Options["Skill Level"]); - int intLevel = int(floatLevel) + - ((floatLevel - int(floatLevel)) * 1024 > rng.rand() % 1024 ? 1 : 0); - Skill skill(intLevel); + Skill skill(Options["Skill Level"], Options["UCI_LimitStrength"] ? int(Options["UCI_Elo"]) : 0); // When playing with strength handicap enable MultiPV search that we will // use behind the scenes to retrieve a set of possible moves. @@ -1780,8 +1777,8 @@ moves_loop: // When in check, search starts here // RootMoves are already sorted by score in descending order Value topScore = rootMoves[0].score; int delta = std::min(topScore - rootMoves[multiPV - 1].score, PawnValueMg); - int weakness = 120 - 2 * level; int maxScore = -VALUE_INFINITE; + double weakness = 120 - 2 * level; // Choose best move. For each move score we add two terms, both dependent on // weakness. One is deterministic and bigger for weaker levels, and one is @@ -1789,8 +1786,8 @@ moves_loop: // When in check, search starts here for (size_t i = 0; i < multiPV; ++i) { // This is our magic formula - int push = ( weakness * int(topScore - rootMoves[i].score) - + delta * (rng.rand() % weakness)) / 128; + int push = int(( weakness * int(topScore - rootMoves[i].score) + + delta * (rng.rand() % int(weakness))) / 128); if (rootMoves[i].score + push >= maxScore) { From 5a223afe4cfdc2cbb0092c86ddc20fd260e1ac0d Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Mon, 1 Nov 2021 06:28:37 +0100 Subject: [PATCH 005/105] Restore development version No functional change --- src/misc.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/misc.cpp b/src/misc.cpp index bb3a641b..f9c12337 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -67,7 +67,7 @@ namespace { /// Version number. If Version is left empty, then compile date in the format /// DD-MM-YY and show in engine_info. -const string Version = "14.1"; +const string Version = ""; /// Our fancy logging facility. The trick here is to replace cin.rdbuf() and /// cout.rdbuf() with two Tie objects that tie cin and cout to a file stream. We From 11c6cf720d4cdd882bc0f2c36e25910cf77fb57b Mon Sep 17 00:00:00 2001 From: lonfom169 Date: Wed, 27 Oct 2021 18:08:24 -0300 Subject: [PATCH 006/105] More futility pruning Expand maximum allowed eval by 50% in futility pruning, above the VALUE_KNOWN_WIN. STC: LLR: 2.95 (-2.94,2.94) <-0.50,2.50> Total: 128208 W: 32534 L: 32192 D: 63482 Ptnml(0-2): 298, 13484, 36216, 13790, 316 https://tests.stockfishchess.org/tests/view/6179c069a9b1d8fbcc4ee716 LTC: LLR: 2.96 (-2.94,2.94) <0.50,3.50> Total: 89816 W: 22645 L: 22265 D: 44906 Ptnml(0-2): 41, 8404, 27650, 8760, 53 https://tests.stockfishchess.org/tests/view/617ad728f411ea45cc39f895 closes https://github.com/official-stockfish/Stockfish/pull/3767 bench: 6804175 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 075be835..a712ce87 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -813,7 +813,7 @@ namespace { if ( !PvNode && depth < 9 && eval - futility_margin(depth, improving) >= beta - && eval < VALUE_KNOWN_WIN) // Do not return unproven wins + && eval < 15000) // 50% larger than VALUE_KNOWN_WIN, but smaller than TB wins. return eval; // Step 8. Null move search with verification search (~40 Elo) From c2b9134c6e7637ea375b4755a6f96dc772c6bb17 Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Thu, 4 Nov 2021 18:35:01 +0300 Subject: [PATCH 007/105] Do more reductions at Pv nodes with low delta This patch increases reduction for PvNodes that have their delta (difference between beta and alpha) significantly reduced compared to what it was at root. passed STC https://tests.stockfishchess.org/tests/view/617f9063af49befdeee40226 LLR: 2.94 (-2.94,2.94) <0.00,2.50> Total: 220840 W: 55752 L: 55150 D: 109938 Ptnml(0-2): 583, 24982, 58712, 25536, 607 passed LTC https://tests.stockfishchess.org/tests/view/61815de959e71df00dcc42ed LLR: 2.95 (-2.94,2.94) <0.50,3.00> Total: 79000 W: 19937 L: 19562 D: 39501 Ptnml(0-2): 36, 8190, 22674, 8563, 37 closes https://github.com/official-stockfish/Stockfish/pull/3774 bench: 6717808 --- src/search.cpp | 6 ++++++ src/thread.h | 1 + 2 files changed, 7 insertions(+) diff --git a/src/search.cpp b/src/search.cpp index a712ce87..46c95ef0 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -625,6 +625,8 @@ namespace { if (alpha >= beta) return alpha; } + else + thisThread->rootDelta = beta - alpha; assert(0 <= ss->ply && ss->ply < MAX_PLY); @@ -1167,6 +1169,10 @@ moves_loop: // When in check, search starts here && bestMoveCount <= 3) r--; + // Increases reduction for PvNodes that have small window + if (PvNode && beta - alpha < thisThread->rootDelta / 4) + r++; + // Decrease reduction if position is or has been on the PV // and node is not likely to fail low. (~3 Elo) if ( ss->ttPv diff --git a/src/thread.h b/src/thread.h index e04d303a..fae866c4 100644 --- a/src/thread.h +++ b/src/thread.h @@ -72,6 +72,7 @@ public: StateInfo rootState; Search::RootMoves rootMoves; Depth rootDepth, completedDepth; + Value rootDelta; CounterMoveHistory counterMoves; ButterflyHistory mainHistory; LowPlyHistory lowPlyHistory; From 45e5e65a28ce7e304c279fabf5f8a83cced73013 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Mon, 1 Nov 2021 08:40:33 +0100 Subject: [PATCH 008/105] do not store qsearch positions in TT as exact. in qsearch don't store positions in TT with the exact flag. passed STC: https://tests.stockfishchess.org/tests/view/617f9a29af49befdeee40231 LLR: 2.95 (-2.94,2.94) <-2.25,0.25> Total: 155568 W: 39003 L: 39022 D: 77543 Ptnml(0-2): 403, 17854, 41305, 17803, 419 passed LTC: https://tests.stockfishchess.org/tests/view/6180d47259e71df00dcc42a5 LLR: 2.94 (-2.94,2.94) <-2.25,0.25> Total: 79640 W: 19993 L: 19910 D: 39737 Ptnml(0-2): 37, 8356, 22957, 8427, 43 closes https://github.com/official-stockfish/Stockfish/pull/3775 Bench: 7531210 --- src/search.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 46c95ef0..6c894c17 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1416,13 +1416,12 @@ moves_loop: // When in check, search starts here Key posKey; Move ttMove, move, bestMove; Depth ttDepth; - Value bestValue, value, ttValue, futilityValue, futilityBase, oldAlpha; + Value bestValue, value, ttValue, futilityValue, futilityBase; bool pvHit, givesCheck, captureOrPromotion; int moveCount; if (PvNode) { - oldAlpha = alpha; // To flag BOUND_EXACT when eval above alpha and no available moves (ss+1)->pv = pv; ss->pv[0] = MOVE_NONE; } @@ -1612,8 +1611,7 @@ moves_loop: // When in check, search starts here // Save gathered info in transposition table tte->save(posKey, value_to_tt(bestValue, ss->ply), pvHit, - bestValue >= beta ? BOUND_LOWER : - PvNode && bestValue > oldAlpha ? BOUND_EXACT : BOUND_UPPER, + bestValue >= beta ? BOUND_LOWER : BOUND_UPPER, ttDepth, bestMove, ss->staticEval); assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE); From a0259d8ab9661b7f625474d2cbe18481ef69bbf2 Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Fri, 5 Nov 2021 13:49:28 +0100 Subject: [PATCH 009/105] Tweak initial aspiration window. Maintain for each root move an exponential average of the search value with a weight ratio of 2:1 (new value vs old values). Then the average score is used as the center of the initial aspiration window instead of the previous score. Stats indicate (see PR) that the deviation for previous score is in general greater than using average score, so later seems a better estimation of the next search value. This is probably the reason this patch succeded besides smoothing the sometimes wild swings in search score. An additional observation is that at higher depth previous score is above but average score below zero. So for average score more/less fail/low highs should be occur than previous score. STC: LLR: 2.97 (-2.94,2.94) <0.00,2.50> Total: 59792 W: 15106 L: 14792 D: 29894 Ptnml(0-2): 144, 6718, 15869, 7010, 155 https://tests.stockfishchess.org/tests/view/61841612d7a085ad008eef06 LTC: LLR: 2.94 (-2.94,2.94) <0.50,3.00> Total: 46448 W: 11835 L: 11537 D: 23076 Ptnml(0-2): 21, 4756, 13374, 5050, 23 https://tests.stockfishchess.org/tests/view/618463abd7a085ad008eef3e closes https://github.com/official-stockfish/Stockfish/pull/3776 Bench: 6719976 --- src/search.cpp | 4 +++- src/search.h | 1 + 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 6c894c17..090a7931 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -376,7 +376,7 @@ void Thread::search() { // Reset aspiration window starting size if (rootDepth >= 4) { - Value prev = rootMoves[pvIdx].previousScore; + Value prev = rootMoves[pvIdx].averageScore; delta = Value(17) + int(prev) * prev / 16384; alpha = std::max(prev - delta,-VALUE_INFINITE); beta = std::min(prev + delta, VALUE_INFINITE); @@ -1280,6 +1280,8 @@ moves_loop: // When in check, search starts here RootMove& rm = *std::find(thisThread->rootMoves.begin(), thisThread->rootMoves.end(), move); + rm.averageScore = rm.averageScore != -VALUE_INFINITE ? (2 * value + rm.averageScore) / 3 : value; + // PV move or new best move? if (moveCount == 1 || value > alpha) { diff --git a/src/search.h b/src/search.h index ba9d0677..7a5d5bdf 100644 --- a/src/search.h +++ b/src/search.h @@ -73,6 +73,7 @@ struct RootMove { Value score = -VALUE_INFINITE; Value previousScore = -VALUE_INFINITE; + Value averageScore = -VALUE_INFINITE; int selDepth = 0; int tbRank = 0; Value tbScore; From 7b278aab9f61620b9dba31896b38aeea1eb911e2 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Sun, 7 Nov 2021 11:01:03 +0100 Subject: [PATCH 010/105] Reduce use of lazyEval In case the evaluation at root is large, discourage the use of lazyEval. This fixes https://github.com/official-stockfish/Stockfish/issues/3772 or at least improves it significantly. In this case, poor play with large odds can be observed, in extreme cases leading to a loss despite large advantage: r1bq1b1r/ppp3p1/3p1nkp/n3p3/2B1P2N/2NPB3/PPP2PPP/R3K2R b KQ - 5 9 With this patch the poor move is only considered up to depth 13, in master up to depth 28. The patch did not pass at LTC with Elo gainer bounds, but with slightly positive Elo nevertheless (95% LOS). STC: LLR: 2.94 (-2.94,2.94) <0.00,2.50> Total: 40368 W: 10318 L: 10041 D: 20009 Ptnml(0-2): 103, 4493, 10725, 4750, 113 https://tests.stockfishchess.org/tests/view/61800ad259e71df00dcc420d LTC: LLR: -2.94 (-2.94,2.94) <0.50,3.00> Total: 212288 W: 52997 L: 52692 D: 106599 Ptnml(0-2): 112, 22038, 61549, 22323, 122 https://tests.stockfishchess.org/tests/view/618050d959e71df00dcc426d closes https://github.com/official-stockfish/Stockfish/pull/3780 Bench: 7127040 --- src/evaluate.cpp | 5 ++++- src/search.cpp | 2 +- src/thread.h | 1 + 3 files changed, 6 insertions(+), 2 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 2f1d5067..a503b0c8 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -988,7 +988,9 @@ namespace { // Early exit if score is high auto lazy_skip = [&](Value lazyThreshold) { - return abs(mg_value(score) + eg_value(score)) > lazyThreshold + pos.non_pawn_material() / 32; + return abs(mg_value(score) + eg_value(score)) > lazyThreshold + + std::abs(pos.this_thread()->bestValue) * 5 / 4 + + pos.non_pawn_material() / 32; }; if (lazy_skip(LazyThreshold1)) @@ -1126,6 +1128,7 @@ std::string Eval::trace(Position& pos) { std::memset(scores, 0, sizeof(scores)); pos.this_thread()->trend = SCORE_ZERO; // Reset any dynamic contempt + pos.this_thread()->bestValue = VALUE_ZERO; // Reset bestValue for lazyEval v = Evaluation(pos).value(); diff --git a/src/search.cpp b/src/search.cpp index 090a7931..11d1df32 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -286,7 +286,7 @@ void Thread::search() { // The latter is needed for statScore and killer initialization. Stack stack[MAX_PLY+10], *ss = stack+7; Move pv[MAX_PLY+1]; - Value bestValue, alpha, beta, delta; + Value alpha, beta, delta; Move lastBestMove = MOVE_NONE; Depth lastBestMoveDepth = 0; MainThread* mainThread = (this == Threads.main() ? Threads.main() : nullptr); diff --git a/src/thread.h b/src/thread.h index fae866c4..38793739 100644 --- a/src/thread.h +++ b/src/thread.h @@ -64,6 +64,7 @@ public: uint64_t nodesLastExplosive; uint64_t nodesLastNormal; std::atomic nodes, tbHits, bestMoveChanges; + Value bestValue; int selDepth, nmpMinPly; Color nmpColor; ExplosionState state; From c4a1390f4e485b8b6a2cf43504a968a3c8a4317d Mon Sep 17 00:00:00 2001 From: bmc4 Date: Mon, 8 Nov 2021 08:46:43 -0300 Subject: [PATCH 011/105] Simplify away the Reverse Move penalty This simplifies the penalty for reverse move introduced in https://github.com/official-stockfish/Stockfish/pull/2294 . STC: LLR: 2.94 (-2.94,2.94) <-2.25,0.25> Total: 81696 W: 20627 L: 20540 D: 40529 Ptnml(0-2): 221, 9390, 21559, 9437, 241 https://tests.stockfishchess.org/tests/view/618810acd7a085ad008ef1cc LTC: LLR: 2.95 (-2.94,2.94) <-2.25,0.25> Total: 44136 W: 11021 L: 10890 D: 22225 Ptnml(0-2): 28, 4570, 12746, 4691, 33 https://tests.stockfishchess.org/tests/view/61885686d7a085ad008ef20b closes https://github.com/official-stockfish/Stockfish/pull/3781 bench: 6547978 --- src/search.cpp | 4 ---- src/types.h | 4 ---- 2 files changed, 8 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 11d1df32..f2e11e35 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1756,10 +1756,6 @@ moves_loop: // When in check, search starts here thisThread->mainHistory[us][from_to(move)] << bonus; update_continuation_histories(ss, pos.moved_piece(move), to_sq(move), bonus); - // Penalty for reversed move in case of moved piece not being a pawn - if (type_of(pos.moved_piece(move)) != PAWN) - thisThread->mainHistory[us][from_to(reverse_move(move))] << -bonus; - // Update countermove history if (is_ok((ss-1)->currentMove)) { diff --git a/src/types.h b/src/types.h index fd643117..02cd19de 100644 --- a/src/types.h +++ b/src/types.h @@ -470,10 +470,6 @@ constexpr Move make_move(Square from, Square to) { return Move((from << 6) + to); } -constexpr Move reverse_move(Move m) { - return make_move(to_sq(m), from_sq(m)); -} - template constexpr Move make(Square from, Square to, PieceType pt = KNIGHT) { return Move(T + ((pt - KNIGHT) << 12) + (from << 6) + to); From 1a5c21dc56a30f4af3979fb47ec3681dc7077195 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Sun, 7 Nov 2021 14:42:46 +0100 Subject: [PATCH 012/105] Tune a few NNUE related scaling parameters passed STC LLR: 2.94 (-2.94,2.94) <0.00,2.50> Total: 102480 W: 26099 L: 25708 D: 50673 Ptnml(0-2): 282, 11637, 27003, 12044, 274 https://tests.stockfishchess.org/tests/view/618820e3d7a085ad008ef1dd passed LTC LLR: 2.93 (-2.94,2.94) <0.50,3.00> Total: 165512 W: 41689 L: 41112 D: 82711 Ptnml(0-2): 82, 17255, 47510, 17822, 87 https://tests.stockfishchess.org/tests/view/6188b470d7a085ad008ef239 closes https://github.com/official-stockfish/Stockfish/pull/3784 Bench: 6339548 --- src/evaluate.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index a503b0c8..9fdadbb7 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -1091,9 +1091,9 @@ Value Eval::evaluate(const Position& pos) { v = Evaluation(pos).value(); // classical else { - int scale = 883 - + 32 * pos.count() - + 32 * pos.non_pawn_material() / 1024; + int scale = 898 + + 24 * pos.count() + + 33 * pos.non_pawn_material() / 1024; v = NNUE::evaluate(pos, true) * scale / 1024; // NNUE @@ -1102,7 +1102,7 @@ Value Eval::evaluate(const Position& pos) { } // Damp down the evaluation linearly when shuffling - v = v * (100 - pos.rule50_count()) / 100; + v = v * (207 - pos.rule50_count()) / 207; // Guarantee evaluation does not hit the tablebase range v = std::clamp(v, VALUE_TB_LOSS_IN_MAX_PLY + 1, VALUE_TB_WIN_IN_MAX_PLY - 1); From 9048ac00db12a9ac48bff9b9eb145b30ff88d984 Mon Sep 17 00:00:00 2001 From: noobpwnftw Date: Sat, 13 Nov 2021 06:38:52 +0800 Subject: [PATCH 013/105] Fix processor group binding under Windows. Starting with Windows Build 20348 the behavior of the numa API has been changed: https://docs.microsoft.com/en-us/windows/win32/procthread/numa-support Old code only worked because there was probably a limit on how many cores/threads can reside within one NUMA node, and the OS creates extra NUMA nodes when necessary, however the actual mechanism of core binding is done by "Processor Groups"(https://docs.microsoft.com/en-us/windows/win32/procthread/processor-groups). With a newer OS, one NUMA node can have many such "Processor Groups" and we should just consistently use the number of groups to bind the threads instead of deriving the topology from the number of NUMA nodes. This change is required to spread threads on all cores on Windows 11 with a 3990X CPU. It has only 1 NUMA node with 2 groups of 64 threads each. closes https://github.com/official-stockfish/Stockfish/pull/3787 No functional change. --- src/misc.cpp | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/misc.cpp b/src/misc.cpp index f9c12337..0af20e10 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -502,7 +502,7 @@ void bindThisThread(size_t) {} int best_group(size_t idx) { int threads = 0; - int nodes = 0; + int groups = 0; int cores = 0; DWORD returnLength = 0; DWORD byteOffset = 0; @@ -530,8 +530,8 @@ int best_group(size_t idx) { while (byteOffset < returnLength) { - if (ptr->Relationship == RelationNumaNode) - nodes++; + if (ptr->Relationship == RelationGroup) + groups += ptr->Group.MaximumGroupCount; else if (ptr->Relationship == RelationProcessorCore) { @@ -546,23 +546,23 @@ int best_group(size_t idx) { free(buffer); - std::vector groups; + std::vector core_groups; - // Run as many threads as possible on the same node until core limit is - // reached, then move on filling the next node. - for (int n = 0; n < nodes; n++) - for (int i = 0; i < cores / nodes; i++) - groups.push_back(n); + // Run as many threads as possible on the same group until core limit is + // reached, then move on filling the next group. + for (int n = 0; n < groups; n++) + for (int i = 0; i < cores / groups; i++) + core_groups.push_back(n); // In case a core has more than one logical processor (we assume 2) and we // have still threads to allocate, then spread them evenly across available - // nodes. + // groups. for (int t = 0; t < threads - cores; t++) - groups.push_back(t % nodes); + core_groups.push_back(t % groups); // If we still have more threads than the total number of logical processors // then return -1 and let the OS to decide what to do. - return idx < groups.size() ? groups[idx] : -1; + return idx < core_groups.size() ? core_groups[idx] : -1; } From f5df517145890ecee3d855e98470241b68645b87 Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Sun, 14 Nov 2021 21:35:00 +0300 Subject: [PATCH 014/105] Simplify Pv nodes related logic in LMR Instead of having 2 separate conditions for Pv nodes reductions we can actually write them together. Despite it's not being strictly logically the same bench actually doesn't change up to depth 20, so them interacting is really rare and thus it's just a removal of extra PvNode check most of the time. passed STC: https://tests.stockfishchess.org/tests/view/618ce27cd7a085ad008ef4e9 LLR: 2.94 (-2.94,2.94) <-2.25,0.25> Total: 37488 W: 9424 L: 9279 D: 18785 Ptnml(0-2): 90, 3903, 10634, 4006, 111 passed LTC: https://tests.stockfishchess.org/tests/view/618d2585d7a085ad008ef527 LLR: 2.95 (-2.94,2.94) <-2.25,0.25> Total: 49968 W: 12449 L: 12331 D: 25188 Ptnml(0-2): 27, 4745, 15309, 4889, 14 closes https://github.com/official-stockfish/Stockfish/pull/3792 Bench: 6339548 --- src/search.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index f2e11e35..fabb0ff0 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1164,15 +1164,12 @@ moves_loop: // When in check, search starts here { Depth r = reduction(improving, depth, moveCount, rangeReduction > 2); - // Decrease reduction if on the PV (~2 Elo) + // Decrease reduction at some PvNodes (~2 Elo) if ( PvNode - && bestMoveCount <= 3) + && bestMoveCount <= 3 + && beta - alpha >= thisThread->rootDelta / 4) r--; - // Increases reduction for PvNodes that have small window - if (PvNode && beta - alpha < thisThread->rootDelta / 4) - r++; - // Decrease reduction if position is or has been on the PV // and node is not likely to fail low. (~3 Elo) if ( ss->ttPv From a5a89b27c8e3225fb453d603bc4515d32bb351c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolet?= Date: Fri, 19 Nov 2021 20:04:35 +0100 Subject: [PATCH 015/105] Introduce Optimism Current master implements a scaling of the raw NNUE output value with a formula equivalent to 'eval = alpha * NNUE_output', where the scale factor alpha varies between 1.8 (for early middle game) and 0.9 (for pure endgames). This feature allows Stockfish to keep material on the board when she thinks she has the advantage, and to seek exchanges and simplifications when she thinks she has to defend. This patch slightly offsets the turning point between these two strategies, by adding to Stockfish's evaluation a small "optimism" value before actually doing the scaling. The effect is that SF will play a little bit more risky, trying to keep the tension a little bit longer when she is defending, and keeping even more material on the board when she has an advantage. We note that this patch is similar in spirit to the old "Contempt" idea we used to have in classical Stockfish, but this implementation differs in two key points: a) it has been tested as an Elo-gainer against master; b) the values output by the search are not changed on average by the implementation (in other words, the optimism value changes the tension/exchange strategy, but a displayed value of 1.0 pawn has the same signification before and after the patch). See the old comment https://github.com/official-stockfish/Stockfish/pull/1361#issuecomment-359165141 for some images illustrating the ideas. ------- finished yellow at STC: LLR: -2.94 (-2.94,2.94) <0.00,2.50> Total: 165048 W: 41705 L: 41611 D: 81732 Ptnml(0-2): 565, 18959, 43245, 19327, 428 https://tests.stockfishchess.org/tests/view/61942a3dcd645dc8291c876b passed LTC: LLR: 2.95 (-2.94,2.94) <0.50,3.00> Total: 121656 W: 30762 L: 30287 D: 60607 Ptnml(0-2): 87, 12558, 35032, 13095, 56 https://tests.stockfishchess.org/tests/view/61962c58cd645dc8291c8877 ------- How to continue from there? a) the shape (slope and amplitude) of the sigmoid used to compute the optimism value could be tweaked to try to gain more Elo, so the parameters of the sigmoid function in line 391 of search.cpp could be tuned with SPSA. Manual tweaking is also possible using this Desmos page: https://www.desmos.com/calculator/jhh83sqq92 b) in a similar vein, with two recents patches affecting the scaling of the NNUE evaluation in evaluate.cpp, now could be a good time to try a round of SPSA tuning of the NNUE network; c) this patch will tend to keep tension in middlegame a little bit longer, so any patch improving the defensive aspect of play via search extensions in risky, tactical positions would be welcome. ------- closes https://github.com/official-stockfish/Stockfish/pull/3797 Bench: 6184852 --- src/evaluate.cpp | 19 +++++++++++++------ src/misc.h | 27 +++++++++++++++++++++++++++ src/search.cpp | 15 ++++++++++----- src/thread.h | 1 + 4 files changed, 51 insertions(+), 11 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 9fdadbb7..c1d3d159 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -1091,11 +1091,15 @@ Value Eval::evaluate(const Position& pos) { v = Evaluation(pos).value(); // classical else { - int scale = 898 - + 24 * pos.count() - + 33 * pos.non_pawn_material() / 1024; + int scale = 898 + + 24 * pos.count() + + 33 * pos.non_pawn_material() / 1024; - v = NNUE::evaluate(pos, true) * scale / 1024; // NNUE + Value nnue = NNUE::evaluate(pos, true); // NNUE + Color stm = pos.side_to_move(); + Value optimism = pos.this_thread()->optimism[stm]; + + v = (nnue + optimism) * scale / 1024 - optimism; if (pos.is_chess960()) v += fix_FRC(pos); @@ -1127,8 +1131,11 @@ std::string Eval::trace(Position& pos) { std::memset(scores, 0, sizeof(scores)); - pos.this_thread()->trend = SCORE_ZERO; // Reset any dynamic contempt - pos.this_thread()->bestValue = VALUE_ZERO; // Reset bestValue for lazyEval + // Reset any global variable used in eval + pos.this_thread()->trend = SCORE_ZERO; + pos.this_thread()->bestValue = VALUE_ZERO; + pos.this_thread()->optimism[WHITE] = VALUE_ZERO; + pos.this_thread()->optimism[BLACK] = VALUE_ZERO; v = Evaluation(pos).value(); diff --git a/src/misc.h b/src/misc.h index 718e5558..c1744130 100644 --- a/src/misc.h +++ b/src/misc.h @@ -138,6 +138,33 @@ private: std::size_t size_ = 0; }; + +/// sigmoid(t, x0, y0, C, P, Q) implements a sigmoid-like function using only integers, +/// with the following properties: +/// +/// - sigmoid is centered in (x0, y0) +/// - sigmoid has amplitude [-P/Q , P/Q] instead of [-1 , +1] +/// - limit is (y0 - P/Q) when t tends to -infinity +/// - limit is (y0 + P/Q) when t tends to +infinity +/// - the slope can be adjusted using C > 0, smaller C giving a steeper sigmoid +/// - the slope of the sigmoid when t = x0 is P/(Q*C) +/// - sigmoid is increasing with t when P > 0 and Q > 0 +/// - to get a decreasing sigmoid, call with -t, or change sign of P +/// - mean value of the sigmoid is y0 +/// +/// Use to draw the sigmoid + +inline int64_t sigmoid(int64_t t, int64_t x0, + int64_t y0, + int64_t C, + int64_t P, + int64_t Q) +{ + assert(C > 0); + return y0 + P * (t-x0) / (Q * (std::abs(t-x0) + C)) ; +} + + /// xorshift64star Pseudo-Random Number Generator /// This class is based on original code written and dedicated /// to the public domain by Sebastiano Vigna (2014). diff --git a/src/search.cpp b/src/search.cpp index fabb0ff0..1dfadd21 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -334,8 +334,10 @@ void Thread::search() { nodesLastExplosive = nodes; nodesLastNormal = nodes; - state = EXPLOSION_NONE; - trend = SCORE_ZERO; + state = EXPLOSION_NONE; + trend = SCORE_ZERO; + optimism[ us] = Value(25); + optimism[~us] = -optimism[us]; int searchAgainCounter = 0; @@ -381,11 +383,14 @@ void Thread::search() { alpha = std::max(prev - delta,-VALUE_INFINITE); beta = std::min(prev + delta, VALUE_INFINITE); - // Adjust trend based on root move's previousScore (dynamic contempt) - int tr = 113 * prev / (abs(prev) + 147); - + // Adjust trend and optimism based on root move's previousScore + int tr = sigmoid(prev, 0, 0, 147, 113, 1); trend = (us == WHITE ? make_score(tr, tr / 2) : -make_score(tr, tr / 2)); + + int opt = sigmoid(prev, 0, 25, 147, 14464, 256); + optimism[ us] = Value(opt); + optimism[~us] = -optimism[us]; } // Start with a small aspiration window and, in the case of a fail diff --git a/src/thread.h b/src/thread.h index 38793739..cd206faa 100644 --- a/src/thread.h +++ b/src/thread.h @@ -68,6 +68,7 @@ public: int selDepth, nmpMinPly; Color nmpColor; ExplosionState state; + Value optimism[COLOR_NB]; Position rootPos; StateInfo rootState; From a943b1d28d673814ee1f3de4a2ae4b8e091f1e4c Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Sun, 21 Nov 2021 20:57:12 +0100 Subject: [PATCH 016/105] Remove appveyor CI retire msvc support and corresponding CI. No active development happens on msvc, and build is much slower or wrong. gcc (mingw) is our toolchain of choice also on windows, and the latter is tested. No functional change --- appveyor.yml | 88 ---------------------------------------------------- 1 file changed, 88 deletions(-) delete mode 100644 appveyor.yml diff --git a/appveyor.yml b/appveyor.yml deleted file mode 100644 index ab608409..00000000 --- a/appveyor.yml +++ /dev/null @@ -1,88 +0,0 @@ -version: 1.0.{build} -clone_depth: 50 - -branches: - only: - - master - -# Operating system (build VM template) -os: Visual Studio 2019 - -# Build platform, i.e. x86, x64, AnyCPU. This setting is optional. -platform: - - x86 - - x64 - -# build Configuration, i.e. Debug, Release, etc. -configuration: - - Debug - - Release - -matrix: - # The build fail immediately once one of the job fails - fast_finish: true - -# Scripts that are called at very beginning, before repo cloning -init: - - cmake --version - - msbuild /version - -before_build: - - ps: | - # Get sources - $src = get-childitem -Path *.cpp -Recurse | select -ExpandProperty FullName - $src = $src -join ' ' - $src = $src.Replace("\", "/") - - # Build CMakeLists.txt - $t = 'cmake_minimum_required(VERSION 3.17)', - 'project(Stockfish)', - 'set(CMAKE_CXX_STANDARD 17)', - 'set(CMAKE_CXX_STANDARD_REQUIRED ON)', - 'set (CMAKE_CXX_EXTENSIONS OFF)', - 'set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_SOURCE_DIR}/src)', - 'set(source_files', $src, ')', - 'add_executable(stockfish ${source_files})' - - # Write CMakeLists.txt withouth BOM - $MyPath = (Get-Item -Path "." -Verbose).FullName + '\CMakeLists.txt' - $Utf8NoBomEncoding = New-Object System.Text.UTF8Encoding $False - [System.IO.File]::WriteAllLines($MyPath, $t, $Utf8NoBomEncoding) - - # Obtain bench reference from git log - $b = git log HEAD | sls "\b[Bb]ench[ :]+[0-9]{7}" | select -first 1 - $bench = $b -match '\D+(\d+)' | % { $matches[1] } - Write-Host "Reference bench:" $bench - $g = "Visual Studio 16 2019" - If (${env:PLATFORM} -eq 'x64') { $a = "x64" } - If (${env:PLATFORM} -eq 'x86') { $a = "Win32" } - cmake -G "${g}" -A ${a} . - Write-Host "Generated files for: " $g $a - -build_script: - - cmake --build . --config %CONFIGURATION% -- /verbosity:minimal - - ps: | - # Download default NNUE net from fishtest - $nnuenet = Get-Content -Path src\evaluate.h | Select-String -CaseSensitive -Pattern "EvalFileDefaultName" | Select-String -CaseSensitive -Pattern "nn-[a-z0-9]{12}.nnue" - $dummy = $nnuenet -match "(?nn-[a-z0-9]{12}.nnue)" - $nnuenet = $Matches.nnuenet - Write-Host "Default net:" $nnuenet - $nnuedownloadurl = "https://tests.stockfishchess.org/api/nn/$nnuenet" - $nnuefilepath = "src\${env:CONFIGURATION}\$nnuenet" - if (Test-Path -Path $nnuefilepath) { - Write-Host "Already available." - } else { - Write-Host "Downloading $nnuedownloadurl to $nnuefilepath" - Invoke-WebRequest -Uri $nnuedownloadurl -OutFile $nnuefilepath - } - -before_test: - - cd src/%CONFIGURATION% - - stockfish bench 2> out.txt >NUL - - ps: | - # Verify bench number - $s = (gc "./out.txt" | out-string) - $r = ($s -match 'Nodes searched \D+(\d+)' | % { $matches[1] }) - Write-Host "Engine bench:" $r - Write-Host "Reference bench:" $bench - If ($r -ne $bench) { exit 1 } From 7218ec4df9fef1146a451b71f0ed3bfd8123c9f9 Mon Sep 17 00:00:00 2001 From: noobpwnftw Date: Sat, 20 Nov 2021 17:57:08 +0800 Subject: [PATCH 017/105] Revert and fix earlier windows NUMA patch revert https://github.com/official-stockfish/Stockfish/commit/9048ac00db12a9ac48bff9b9eb145b30ff88d984 due to core spread problem and fix new OS compatibility with another method. This code assumes that if one NUMA node has more than one processor groups, they are created equal(having equal amount of cores assigned to each of the groups), and also the total number of available cores contained in such groups are equal to the number of available cores within one NUMA node because of how best_node function works. closes https://github.com/official-stockfish/Stockfish/pull/3798 fixes https://github.com/official-stockfish/Stockfish/pull/3787 No functional change. --- src/misc.cpp | 54 +++++++++++++++++++++++++++++++++------------------- 1 file changed, 34 insertions(+), 20 deletions(-) diff --git a/src/misc.cpp b/src/misc.cpp index 0af20e10..4dfa9f0c 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -36,6 +36,7 @@ typedef bool(*fun1_t)(LOGICAL_PROCESSOR_RELATIONSHIP, PSYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX, PDWORD); typedef bool(*fun2_t)(USHORT, PGROUP_AFFINITY); typedef bool(*fun3_t)(HANDLE, CONST GROUP_AFFINITY*, PGROUP_AFFINITY); +typedef bool(*fun4_t)(USHORT, PGROUP_AFFINITY, USHORT, PUSHORT); } #endif @@ -495,14 +496,14 @@ void bindThisThread(size_t) {} #else -/// best_group() retrieves logical processor information using Windows specific -/// API and returns the best group id for the thread with index idx. Original +/// best_node() retrieves logical processor information using Windows specific +/// API and returns the best node id for the thread with index idx. Original /// code from Texel by Peter Ă–sterlund. -int best_group(size_t idx) { +int best_node(size_t idx) { int threads = 0; - int groups = 0; + int nodes = 0; int cores = 0; DWORD returnLength = 0; DWORD byteOffset = 0; @@ -530,8 +531,8 @@ int best_group(size_t idx) { while (byteOffset < returnLength) { - if (ptr->Relationship == RelationGroup) - groups += ptr->Group.MaximumGroupCount; + if (ptr->Relationship == RelationNumaNode) + nodes++; else if (ptr->Relationship == RelationProcessorCore) { @@ -546,23 +547,23 @@ int best_group(size_t idx) { free(buffer); - std::vector core_groups; + std::vector groups; - // Run as many threads as possible on the same group until core limit is - // reached, then move on filling the next group. - for (int n = 0; n < groups; n++) - for (int i = 0; i < cores / groups; i++) - core_groups.push_back(n); + // Run as many threads as possible on the same node until core limit is + // reached, then move on filling the next node. + for (int n = 0; n < nodes; n++) + for (int i = 0; i < cores / nodes; i++) + groups.push_back(n); // In case a core has more than one logical processor (we assume 2) and we // have still threads to allocate, then spread them evenly across available - // groups. + // nodes. for (int t = 0; t < threads - cores; t++) - core_groups.push_back(t % groups); + groups.push_back(t % nodes); // If we still have more threads than the total number of logical processors // then return -1 and let the OS to decide what to do. - return idx < core_groups.size() ? core_groups[idx] : -1; + return idx < groups.size() ? groups[idx] : -1; } @@ -571,22 +572,35 @@ int best_group(size_t idx) { void bindThisThread(size_t idx) { // Use only local variables to be thread-safe - int group = best_group(idx); + int node = best_node(idx); - if (group == -1) + if (node == -1) return; // Early exit if the needed API are not available at runtime HMODULE k32 = GetModuleHandle("Kernel32.dll"); auto fun2 = (fun2_t)(void(*)())GetProcAddress(k32, "GetNumaNodeProcessorMaskEx"); auto fun3 = (fun3_t)(void(*)())GetProcAddress(k32, "SetThreadGroupAffinity"); + auto fun4 = (fun4_t)(void(*)())GetProcAddress(k32, "GetNumaNodeProcessorMask2"); if (!fun2 || !fun3) return; - GROUP_AFFINITY affinity; - if (fun2(group, &affinity)) - fun3(GetCurrentThread(), &affinity, nullptr); + if (!fun4) { + GROUP_AFFINITY affinity; + if (fun2(node, &affinity)) + fun3(GetCurrentThread(), &affinity, nullptr); + } else { + // If a numa node has more than one processor group, we assume they are + // sized equal and we spread threads evenly across the groups. + USHORT elements, returnedElements; + elements = GetMaximumProcessorGroupCount(); + GROUP_AFFINITY *affinity = (GROUP_AFFINITY*)malloc( + elements * sizeof(GROUP_AFFINITY)); + if (fun4(node, affinity, elements, &returnedElements)) + fun3(GetCurrentThread(), &affinity[idx % returnedElements], nullptr); + free(affinity); + } } #endif From 092b27a6d0174f619fff9a53099ac9fdc5c2cb4e Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Tue, 23 Nov 2021 20:40:32 +0100 Subject: [PATCH 018/105] Less futility pruning. Disable futility pruning at former PV nodes stored in the transposition table. STC: LLR: 2.96 (-2.94,2.94) <0.00,2.50> Total: 102256 W: 25708 L: 25318 D: 51230 Ptnml(0-2): 276, 11511, 27168, 11893, 280 https://tests.stockfishchess.org/tests/view/61990b3135c7c6348cb602db LTC: LLR: 2.96 (-2.94,2.94) <0.50,3.00> Total: 183304 W: 46027 L: 45408 D: 91869 Ptnml(0-2): 96, 19029, 52778, 19658, 91 https://tests.stockfishchess.org/tests/view/619a0d1b35c7c6348cb603bc closes https://github.com/official-stockfish/Stockfish/pull/3804 Bench: 7334766 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 1dfadd21..92ec9eca 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -817,7 +817,7 @@ namespace { // Step 7. Futility pruning: child node (~50 Elo). // The depth condition is important for mate finding. - if ( !PvNode + if ( !ss->ttPv && depth < 9 && eval - futility_margin(depth, improving) >= beta && eval < 15000) // 50% larger than VALUE_KNOWN_WIN, but smaller than TB wins. From 0ac8aca893dd2052f8433e0b4a3d65073266b00f Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Thu, 25 Nov 2021 20:55:52 +0300 Subject: [PATCH 019/105] Use fraction of history heuristics in futility pruning This idea is somewhat of a respin of smth we had in futility pruning and that was simplified away - dependence of it not only on static evaluation of position but also on move history heuristics. Instead of aborting it when they are high there we use fraction of their sum to adjust static eval pruning criteria. passed STC https://tests.stockfishchess.org/tests/view/619bd438c0a4ea18ba95a27d LLR: 2.93 (-2.94,2.94) <0.00,2.50> Total: 113704 W: 29284 L: 28870 D: 55550 Ptnml(0-2): 357, 12884, 30044, 13122, 445 passed LTC https://tests.stockfishchess.org/tests/view/619cb8f0c0a4ea18ba95a334 LLR: 2.96 (-2.94,2.94) <0.50,3.00> Total: 147136 W: 37307 L: 36770 D: 73059 Ptnml(0-2): 107, 15279, 42265, 15804, 113 closes https://github.com/official-stockfish/Stockfish/pull/3805 bench 6777918 --- src/search.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 92ec9eca..12c89de4 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1054,17 +1054,19 @@ moves_loop: // When in check, search starts here } else { + int history = (*contHist[0])[movedPiece][to_sq(move)] + + (*contHist[1])[movedPiece][to_sq(move)] + + (*contHist[3])[movedPiece][to_sq(move)]; + // Continuation history based pruning (~20 Elo) - if (lmrDepth < 5 - && (*contHist[0])[movedPiece][to_sq(move)] - + (*contHist[1])[movedPiece][to_sq(move)] - + (*contHist[3])[movedPiece][to_sq(move)] < -3000 * depth + 3000) + if ( lmrDepth < 5 + && history < -3000 * depth + 3000) continue; // Futility pruning: parent node (~5 Elo) if ( !ss->inCheck && lmrDepth < 8 - && ss->staticEval + 172 + 145 * lmrDepth <= alpha) + && ss->staticEval + 172 + 145 * lmrDepth + history / 256 <= alpha) continue; // Prune moves with negative SEE (~20 Elo) From 9ee58dc7a75d7cdc09935f8782e927bb19700afe Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Wed, 24 Nov 2021 22:13:35 +0100 Subject: [PATCH 020/105] Update default net to nn-3678835b1d3d.nnue New net trained with nnue-pytorch, started from the master net on a data set of Leela (T60.binpack+T74.binpck) and Stockfish data (wrongIsRight_nodes5000pv2.binpack), available as a single interleaved binpack: https://drive.google.com/file/d/12uWZIA3F2cNbraAzQNb1jgf3tq_6HkTr/view?usp=sharing The nnue-pytorch branch used is https://github.com/vondele/nnue-pytorch/tree/wdl, which has the new feature to filter positions based on the likelihood of the current evaluation leading to the game outcome. It should make it less likely to try to learn from misevaluated positions. Standard options have been used, starting from the master net: --gpus 1 --threads 4 --num-workers 4 --batch-size 16384 --progress_bar_refresh_rate 300 --smart-fen-skipping --random-fen-skipping 12 --features=HalfKAv2_hm^ --lambda=1.0 Testing with games shows neutral Elo at STC, and good performance at LTC: STC: https://tests.stockfishchess.org/tests/view/619eb597c0a4ea18ba95a4dc ELO: -0.44 +-1.8 (95%) LOS: 31.2% Total: 40000 W: 10447 L: 10498 D: 19055 Ptnml(0-2): 254, 4576, 10260, 4787, 123 LTC: https://tests.stockfishchess.org/tests/view/619f6e87c0a4ea18ba95a53f ELO: 3.30 +-1.8 (95%) LOS: 100.0% Total: 33062 W: 8560 L: 8246 D: 16256 Ptnml(0-2): 54, 3358, 9352, 3754, 13 passed LTC SPRT: https://tests.stockfishchess.org/tests/view/61a0864e8967bbf894416e65 LLR: 2.94 (-2.94,2.94) <0.50,3.00> Total: 29376 W: 7663 L: 7396 D: 14317 Ptnml(0-2): 67, 3017, 8205, 3380, 19 closes https://github.com/official-stockfish/Stockfish/pull/3808 Bench: 7011501 --- src/evaluate.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/evaluate.h b/src/evaluate.h index e2cdb210..e5340c7f 100644 --- a/src/evaluate.h +++ b/src/evaluate.h @@ -39,7 +39,7 @@ namespace Eval { // The default net name MUST follow the format nn-[SHA256 first 12 digits].nnue // for the build process (profile-build and fishtest) to work. Do not change the // name of the macro, as it is used in the Makefile. - #define EvalFileDefaultName "nn-13406b1dcbe0.nnue" + #define EvalFileDefaultName "nn-3678835b1d3d.nnue" namespace NNUE { From 4bb11e823fb292b8cc81ac873ccca9827af462be Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Fri, 26 Nov 2021 22:10:00 +0100 Subject: [PATCH 021/105] Tune NNUE scaling params passed STC: https://tests.stockfishchess.org/tests/view/61a156f89e83391467a2b2cc LLR: 2.94 (-2.94,2.94) <0.00,2.50> Total: 22816 W: 5896 L: 5646 D: 11274 Ptnml(0-2): 55, 2567, 5961, 2723, 102 passed LTC: https://tests.stockfishchess.org/tests/view/61a1cf3d9e83391467a2b30b LLR: 2.94 (-2.94,2.94) <0.50,3.00> Total: 17904 W: 4658 L: 4424 D: 8822 Ptnml(0-2): 6, 1821, 5079, 2025, 21 closes https://github.com/official-stockfish/Stockfish/pull/3811 Bench: 7218806 --- src/evaluate.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index c1d3d159..1dc701cf 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -1091,9 +1091,9 @@ Value Eval::evaluate(const Position& pos) { v = Evaluation(pos).value(); // classical else { - int scale = 898 - + 24 * pos.count() - + 33 * pos.non_pawn_material() / 1024; + int scale = 1049 + + 8 * pos.count() + + 20 * pos.non_pawn_material() / 1024; Value nnue = NNUE::evaluate(pos, true); // NNUE Color stm = pos.side_to_move(); From 8bb5a436b240d22e3e9729a1cd094169941afd7c Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Sat, 27 Nov 2021 16:38:37 +0300 Subject: [PATCH 022/105] Adjust usage of history in futility pruning This patch refines 0ac8aca893dd2052f8433e0b4a3d65073266b00f that uses history heuristics in futility pruning. Now it adds main history of the move to in and also increases effect by factor of 2. passed STC https://tests.stockfishchess.org/tests/view/61a156829e83391467a2b2c9 LLR: 2.94 (-2.94,2.94) <0.00,2.50> Total: 68464 W: 17920 L: 17587 D: 32957 Ptnml(0-2): 239, 7711, 18025, 7992, 265 passed LTC https://tests.stockfishchess.org/tests/view/61a1bde99e83391467a2b305 LLR: 2.95 (-2.94,2.94) <0.50,3.00> Total: 26088 W: 6926 L: 6674 D: 12488 Ptnml(0-2): 18, 2619, 7531, 2845, 31 closes https://github.com/official-stockfish/Stockfish/pull/3812 bench 6804653 --- src/search.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 12c89de4..8f9fa62c 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1063,10 +1063,12 @@ moves_loop: // When in check, search starts here && history < -3000 * depth + 3000) continue; + history += thisThread->mainHistory[us][from_to(move)]; + // Futility pruning: parent node (~5 Elo) if ( !ss->inCheck && lmrDepth < 8 - && ss->staticEval + 172 + 145 * lmrDepth + history / 256 <= alpha) + && ss->staticEval + 172 + 145 * lmrDepth + history / 128 <= alpha) continue; // Prune moves with negative SEE (~20 Elo) From af050e5eed43f2d360bc6d38a9d9ef64b6ce6ad8 Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Sun, 28 Nov 2021 15:19:18 +0300 Subject: [PATCH 023/105] Refine futility pruning for parent nodes This patch is a result of refining of tuning vondele did after new net passed and some hand-made values adjustements - excluding changes in other pruning heuristics and rounding value of history divisor to the nearest power of 2. With this patch futility pruning becomes more aggressive and history influence on it is doubled again. passed STC https://tests.stockfishchess.org/tests/view/61a2c4c1a26505c2278c150d LLR: 2.94 (-2.94,2.94) <0.00,2.50> Total: 33848 W: 8841 L: 8574 D: 16433 Ptnml(0-2): 100, 3745, 8988, 3970, 121 passed LTC https://tests.stockfishchess.org/tests/view/61a327ffa26505c2278c26d9 LLR: 2.94 (-2.94,2.94) <0.50,3.00> Total: 22272 W: 5856 L: 5614 D: 10802 Ptnml(0-2): 12, 2230, 6412, 2468, 14 closes https://github.com/official-stockfish/Stockfish/pull/3814 bench 6302543 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 8f9fa62c..807d2614 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1068,7 +1068,7 @@ moves_loop: // When in check, search starts here // Futility pruning: parent node (~5 Elo) if ( !ss->inCheck && lmrDepth < 8 - && ss->staticEval + 172 + 145 * lmrDepth + history / 128 <= alpha) + && ss->staticEval + 142 + 139 * lmrDepth + history / 64 <= alpha) continue; // Prune moves with negative SEE (~20 Elo) From e4a0c6c75950bf27b6dc32490a1102499643126b Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Sun, 28 Nov 2021 19:26:10 +0100 Subject: [PATCH 024/105] Update default net to nn-4f56ecfca5b7.nnue New net trained with nnue-pytorch, started from a master net on a data set of Leela (T60.binpack+T74.binpck) Stockfish data (wrongIsRight_nodes5000pv2.binpack), and Michael Babigian's conversion of T60 Leela data (including TB7 rescoring) (farseer.binpack) available as a single interleaved binpack: https://drive.google.com/file/d/1_sQoWBl31WAxNXma2v45004CIVltytP8/view?usp=sharing The nnue-pytorch branch used is https://github.com/vondele/nnue-pytorch/tree/wdl passed STC: https://tests.stockfishchess.org/tests/view/61a3cc729f0c43dae1c71f1b LLR: 2.95 (-2.94,2.94) <0.00,2.50> Total: 49152 W: 12842 L: 12544 D: 23766 Ptnml(0-2): 154, 5542, 12904, 5804, 172 passed LTC: https://tests.stockfishchess.org/tests/view/61a43c6260afd064f2d724f1 LLR: 2.96 (-2.94,2.94) <0.50,3.00> Total: 25528 W: 6676 L: 6425 D: 12427 Ptnml(0-2): 9, 2593, 7315, 2832, 15 closes https://github.com/official-stockfish/Stockfish/pull/3816 Bench: 6885242 --- src/evaluate.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/evaluate.h b/src/evaluate.h index e5340c7f..77c3b4e7 100644 --- a/src/evaluate.h +++ b/src/evaluate.h @@ -39,7 +39,7 @@ namespace Eval { // The default net name MUST follow the format nn-[SHA256 first 12 digits].nnue // for the build process (profile-build and fishtest) to work. Do not change the // name of the macro, as it is used in the Makefile. - #define EvalFileDefaultName "nn-3678835b1d3d.nnue" + #define EvalFileDefaultName "nn-4f56ecfca5b7.nnue" namespace NNUE { From ca3c1c5f3a5f011edd04af856cdd59bdaefe423d Mon Sep 17 00:00:00 2001 From: noobpwnftw Date: Tue, 30 Nov 2021 09:22:07 +0800 Subject: [PATCH 025/105] Enable compilation on older Windows systems Improve compatibility of the last NUMA patch when running under older versions of Windows, for instance Windows Server 2003. Reported by user "g3g6" in the following comments: https://github.com/official-stockfish/Stockfish/commit/7218ec4df9fef1146a451b71f0ed3bfd8123c9f9 Closes https://github.com/official-stockfish/Stockfish/pull/3821 No functional change --- src/misc.cpp | 27 ++++++++++++++++----------- src/search.cpp | 2 +- 2 files changed, 17 insertions(+), 12 deletions(-) diff --git a/src/misc.cpp b/src/misc.cpp index 4dfa9f0c..294b7c8f 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -37,6 +37,7 @@ typedef bool(*fun1_t)(LOGICAL_PROCESSOR_RELATIONSHIP, typedef bool(*fun2_t)(USHORT, PGROUP_AFFINITY); typedef bool(*fun3_t)(HANDLE, CONST GROUP_AFFINITY*, PGROUP_AFFINITY); typedef bool(*fun4_t)(USHORT, PGROUP_AFFINITY, USHORT, PUSHORT); +typedef WORD(*fun5_t)(); } #endif @@ -514,7 +515,8 @@ int best_node(size_t idx) { if (!fun1) return -1; - // First call to get returnLength. We expect it to fail due to null buffer + // First call to GetLogicalProcessorInformationEx() to get returnLength. + // We expect the call to fail due to null buffer. if (fun1(RelationAll, nullptr, &returnLength)) return -1; @@ -522,7 +524,7 @@ int best_node(size_t idx) { SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX *buffer, *ptr; ptr = buffer = (SYSTEM_LOGICAL_PROCESSOR_INFORMATION_EX*)malloc(returnLength); - // Second call, now we expect to succeed + // Second call to GetLogicalProcessorInformationEx(), now we expect to succeed if (!fun1(RelationAll, buffer, &returnLength)) { free(buffer); @@ -582,23 +584,26 @@ void bindThisThread(size_t idx) { auto fun2 = (fun2_t)(void(*)())GetProcAddress(k32, "GetNumaNodeProcessorMaskEx"); auto fun3 = (fun3_t)(void(*)())GetProcAddress(k32, "SetThreadGroupAffinity"); auto fun4 = (fun4_t)(void(*)())GetProcAddress(k32, "GetNumaNodeProcessorMask2"); + auto fun5 = (fun5_t)(void(*)())GetProcAddress(k32, "GetMaximumProcessorGroupCount"); if (!fun2 || !fun3) return; - if (!fun4) { + if (!fun4 || !fun5) + { GROUP_AFFINITY affinity; - if (fun2(node, &affinity)) - fun3(GetCurrentThread(), &affinity, nullptr); - } else { + if (fun2(node, &affinity)) // GetNumaNodeProcessorMaskEx + fun3(GetCurrentThread(), &affinity, nullptr); // SetThreadGroupAffinity + } + else + { // If a numa node has more than one processor group, we assume they are // sized equal and we spread threads evenly across the groups. USHORT elements, returnedElements; - elements = GetMaximumProcessorGroupCount(); - GROUP_AFFINITY *affinity = (GROUP_AFFINITY*)malloc( - elements * sizeof(GROUP_AFFINITY)); - if (fun4(node, affinity, elements, &returnedElements)) - fun3(GetCurrentThread(), &affinity[idx % returnedElements], nullptr); + elements = fun5(); // GetMaximumProcessorGroupCount + GROUP_AFFINITY *affinity = (GROUP_AFFINITY*)malloc(elements * sizeof(GROUP_AFFINITY)); + if (fun4(node, affinity, elements, &returnedElements)) // GetNumaNodeProcessorMask2 + fun3(GetCurrentThread(), &affinity[idx % returnedElements], nullptr); // SetThreadGroupAffinity free(affinity); } } diff --git a/src/search.cpp b/src/search.cpp index 807d2614..6e41f48d 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1063,7 +1063,7 @@ moves_loop: // When in check, search starts here && history < -3000 * depth + 3000) continue; - history += thisThread->mainHistory[us][from_to(move)]; + history += thisThread->mainHistory[us][from_to(move)]; // Futility pruning: parent node (~5 Elo) if ( !ss->inCheck From 282644f1413db0ccb58e2e1793d5007c58ff8ce2 Mon Sep 17 00:00:00 2001 From: pb00067 Date: Fri, 26 Nov 2021 08:03:15 +0100 Subject: [PATCH 026/105] Remove depth dependence and use same limit (2000) as stat_bonus STC: https://tests.stockfishchess.org/tests/view/619df59dc0a4ea18ba95a424 LLR: 2.96 (-2.94,2.94) <-2.25,0.25> Total: 83728 W: 21329 L: 21242 D: 41157 Ptnml(0-2): 297, 9669, 21847, 9752, 299 LTC: https://tests.stockfishchess.org/tests/view/619e64d7c0a4ea18ba95a475 LLR: 2.94 (-2.94,2.94) <-2.25,0.25> Total: 79888 W: 20238 L: 20155 D: 39495 Ptnml(0-2): 57, 8391, 22980, 8444, 73 closes https://github.com/official-stockfish/Stockfish/pull/3806 bench: 6792010 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 6e41f48d..c4ed7337 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -801,7 +801,7 @@ namespace { // Use static evaluation difference to improve quiet move ordering if (is_ok((ss-1)->currentMove) && !(ss-1)->inCheck && !priorCapture) { - int bonus = std::clamp(-depth * 4 * int((ss-1)->staticEval + ss->staticEval), -1000, 1000); + int bonus = std::clamp(-16 * int((ss-1)->staticEval + ss->staticEval), -2000, 2000); thisThread->mainHistory[~us][from_to((ss-1)->currentMove)] << bonus; } From 64f21ecdae0402bfde4e9f4e61097c99bcae343e Mon Sep 17 00:00:00 2001 From: hengyu Date: Fri, 26 Nov 2021 18:25:03 +0800 Subject: [PATCH 027/105] Small clean-up remove unneeded calculation. closes https://github.com/official-stockfish/Stockfish/pull/3807 No functional change. --- src/nnue/evaluate_nnue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nnue/evaluate_nnue.cpp b/src/nnue/evaluate_nnue.cpp index 6e40deab..bd473294 100644 --- a/src/nnue/evaluate_nnue.cpp +++ b/src/nnue/evaluate_nnue.cpp @@ -234,7 +234,7 @@ namespace Stockfish::Eval::NNUE { { buffer[1] = '0' + cp / 10000; cp %= 10000; buffer[2] = '0' + cp / 1000; cp %= 1000; - buffer[3] = '0' + cp / 100; cp %= 100; + buffer[3] = '0' + cp / 100; buffer[4] = ' '; } else if (cp >= 1000) From 4b86ef8c4f8755850b38f2eca026cb9da20c4d01 Mon Sep 17 00:00:00 2001 From: Michael Ortmann <41313082+michaelortmann@users.noreply.github.com> Date: Tue, 30 Nov 2021 21:01:34 +0100 Subject: [PATCH 028/105] Fix typos in comments, adjust readme closes https://github.com/official-stockfish/Stockfish/pull/3822 also adjusts readme as requested in https://github.com/official-stockfish/Stockfish/pull/3816 No functional change --- README.md | 8 ++++++-- src/nnue/nnue_common.h | 2 +- src/syzygy/tbprobe.cpp | 20 ++++++++++---------- src/syzygy/tbprobe.h | 2 +- src/tune.h | 2 +- tests/reprosearch.sh | 2 +- 6 files changed, 20 insertions(+), 16 deletions(-) diff --git a/README.md b/README.md index 79db8170..330d19ed 100644 --- a/README.md +++ b/README.md @@ -175,8 +175,12 @@ on the evaluations of millions of positions at moderate search depth. The NNUE evaluation was first introduced in shogi, and ported to Stockfish afterward. It can be evaluated efficiently on CPUs, and exploits the fact that only parts of the neural network need to be updated after a typical chess move. -[The nodchip repository](https://github.com/nodchip/Stockfish) provides additional -tools to train and develop the NNUE networks. On CPUs supporting modern vector instructions +[The nodchip repository](https://github.com/nodchip/Stockfish) provided the first version of +the needed tools to train and develop the NNUE networks. Today, more advanced training tools are available +in [the nnue-pytorch repository](https://github.com/glinscott/nnue-pytorch/), while data generation tools +are available in [a dedicated branch](https://github.com/official-stockfish/Stockfish/tree/tools). + +On CPUs supporting modern vector instructions (avx2 and similar), the NNUE evaluation results in much stronger playing strength, even if the nodes per second computed by the engine is somewhat lower (roughly 80% of nps is typical). diff --git a/src/nnue/nnue_common.h b/src/nnue/nnue_common.h index 75ac7862..74eaae17 100644 --- a/src/nnue/nnue_common.h +++ b/src/nnue/nnue_common.h @@ -109,7 +109,7 @@ namespace Stockfish::Eval::NNUE { // write_little_endian() is our utility to write an integer (signed or unsigned, any size) // to a stream in little-endian order. We swap the byte order before the write if - // necessary to always write in little endian order, independantly of the byte + // necessary to always write in little endian order, independently of the byte // ordering of the compiling machine. template inline void write_little_endian(std::ostream& stream, IntType value) { diff --git a/src/syzygy/tbprobe.cpp b/src/syzygy/tbprobe.cpp index 96b2970f..41e867c0 100644 --- a/src/syzygy/tbprobe.cpp +++ b/src/syzygy/tbprobe.cpp @@ -769,7 +769,7 @@ Ret do_probe_table(const Position& pos, T* entry, WDLScore wdl, ProbeState* resu goto encode_remaining; // With pawns we have finished special treatments } - // In positions withouth pawns, we further flip the squares to ensure leading + // In positions without pawns, we further flip the squares to ensure leading // piece is below RANK_5. if (rank_of(squares[0]) > RANK_4) for (int i = 0; i < size; ++i) @@ -812,7 +812,7 @@ Ret do_probe_table(const Position& pos, T* entry, WDLScore wdl, ProbeState* resu // Rs "together" in 62 * 61 / 2 ways (we divide by 2 because rooks can be // swapped and still get the same position.) // - // In case we have at least 3 unique pieces (inlcuded kings) we encode them + // In case we have at least 3 unique pieces (included kings) we encode them // together. if (entry->hasUniquePieces) { @@ -827,7 +827,7 @@ Ret do_probe_table(const Position& pos, T* entry, WDLScore wdl, ProbeState* resu + (squares[1] - adjust1)) * 62 + squares[2] - adjust2; - // First piece is on a1-h8 diagonal, second below: map this occurence to + // First piece is on a1-h8 diagonal, second below: map this occurrence to // 6 to differentiate from the above case, rank_of() maps a1-d4 diagonal // to 0...3 and finally MapB1H1H7[] maps the b1-h1-h7 triangle to 0..27. else if (off_A1H8(squares[1])) @@ -857,7 +857,7 @@ encode_remaining: idx *= d->groupIdx[0]; Square* groupSq = squares + d->groupLen[0]; - // Encode remainig pawns then pieces according to square, in ascending order + // Encode remaining pawns then pieces according to square, in ascending order bool remainingPawns = entry->hasPawns && entry->pawnCount[1]; while (d->groupLen[++next]) @@ -885,7 +885,7 @@ encode_remaining: // Group together pieces that will be encoded together. The general rule is that // a group contains pieces of same type and color. The exception is the leading -// group that, in case of positions withouth pawns, can be formed by 3 different +// group that, in case of positions without pawns, can be formed by 3 different // pieces (default) or by the king pair when there is not a unique piece apart // from the kings. When there are pawns, pawns are always first in pieces[]. // @@ -917,7 +917,7 @@ void set_groups(T& e, PairsData* d, int order[], File f) { // // This ensures unique encoding for the whole position. The order of the // groups is a per-table parameter and could not follow the canonical leading - // pawns/pieces -> remainig pawns -> remaining pieces. In particular the + // pawns/pieces -> remaining pawns -> remaining pieces. In particular the // first group is at order[0] position and the remaining pawns, when present, // are at order[1] position. bool pp = e.hasPawns && e.pawnCount[1]; // Pawns on both sides @@ -937,7 +937,7 @@ void set_groups(T& e, PairsData* d, int order[], File f) { d->groupIdx[1] = idx; idx *= Binomial[d->groupLen[1]][48 - d->groupLen[0]]; } - else // Remainig pieces + else // Remaining pieces { d->groupIdx[next] = idx; idx *= Binomial[d->groupLen[next]][freeSquares]; @@ -947,7 +947,7 @@ void set_groups(T& e, PairsData* d, int order[], File f) { d->groupIdx[n] = idx; } -// In Recursive Pairing each symbol represents a pair of childern symbols. So +// In Recursive Pairing each symbol represents a pair of children symbols. So // read d->btree[] symbols data and expand each one in his left and right child // symbol until reaching the leafs that represent the symbol value. uint8_t set_symlen(PairsData* d, Sym s, std::vector& visited) { @@ -1317,7 +1317,7 @@ void Tablebases::init(const std::string& paths) { for (auto p : bothOnDiagonal) MapKK[p.first][p.second] = code++; - // Binomial[] stores the Binomial Coefficents using Pascal rule. There + // Binomial[] stores the Binomial Coefficients using Pascal rule. There // are Binomial[k][n] ways to choose k elements from a set of n elements. Binomial[0][0] = 1; @@ -1337,7 +1337,7 @@ void Tablebases::init(const std::string& paths) { for (int leadPawnsCnt = 1; leadPawnsCnt <= 5; ++leadPawnsCnt) for (File f = FILE_A; f <= FILE_D; ++f) { - // Restart the index at every file because TB table is splitted + // Restart the index at every file because TB table is split // by file, so we can reuse the same index for different files. int idx = 0; diff --git a/src/syzygy/tbprobe.h b/src/syzygy/tbprobe.h index 56734af9..cf61b767 100644 --- a/src/syzygy/tbprobe.h +++ b/src/syzygy/tbprobe.h @@ -38,7 +38,7 @@ enum WDLScore { // Possible states after a probing operation enum ProbeState { FAIL = 0, // Probe failed (missing file table) - OK = 1, // Probe succesful + OK = 1, // Probe successful CHANGE_STM = -1, // DTZ should check the other side ZEROING_BEST_MOVE = 2 // Best move zeroes DTZ (capture or pawn move) }; diff --git a/src/tune.h b/src/tune.h index b5c715b3..53d52a65 100644 --- a/src/tune.h +++ b/src/tune.h @@ -84,7 +84,7 @@ class Tune { static Tune& instance() { static Tune t; return t; } // Singleton - // Use polymorphism to accomodate Entry of different types in the same vector + // Use polymorphism to accommodate Entry of different types in the same vector struct EntryBase { virtual ~EntryBase() = default; virtual void init_option() = 0; diff --git a/tests/reprosearch.sh b/tests/reprosearch.sh index c1167f7f..e16ba4ae 100755 --- a/tests/reprosearch.sh +++ b/tests/reprosearch.sh @@ -43,7 +43,7 @@ cat << EOF > repeat.exp expect eof EOF -# to increase the likelyhood of finding a non-reproducible case, +# to increase the likelihood of finding a non-reproducible case, # the allowed number of nodes are varied systematically for i in `seq 1 20` do From 95a2ac1e073a6f7c3af8aeef2fc4fe8cbd6650cf Mon Sep 17 00:00:00 2001 From: bmc4 Date: Mon, 29 Nov 2021 09:30:07 -0300 Subject: [PATCH 029/105] Simplify reduction on rootNode when bestMoveChanges is high The reduction introduced in #3736 also consider on rootNode, so we don't have to reduce again. STC: LLR: 2.94 (-2.94,2.94) <-2.25,0.25> Total: 28736 W: 7494 L: 7329 D: 13913 Ptnml(0-2): 95, 3247, 7503, 3444, 79 https://tests.stockfishchess.org/tests/view/61a3abe01b7fdf52228e74d8 LTC: LLR: 2.94 (-2.94,2.94) <-2.25,0.25> Total: 47816 W: 12434 L: 12308 D: 23074 Ptnml(0-2): 37, 4972, 13755, 5116, 28 https://tests.stockfishchess.org/tests/view/61a3c3e39f0c43dae1c71d71 closes https://github.com/official-stockfish/Stockfish/pull/3817 bench: 6331638 --- src/search.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index c4ed7337..70dc4b21 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1185,8 +1185,8 @@ moves_loop: // When in check, search starts here && !likelyFailLow) r -= 2; - // Increase reduction at root and non-PV nodes when the best move does not change frequently - if ( (rootNode || !PvNode) + // Increase reduction at non-PV nodes when the best move does not change frequently + if ( !PvNode && thisThread->bestMoveChanges <= 2) r++; From c1f9a359e8e319d832ee5a55277dab996dd29d25 Mon Sep 17 00:00:00 2001 From: bmc4 Date: Mon, 29 Nov 2021 14:51:35 -0300 Subject: [PATCH 030/105] Correctly reset bestMoveChanges for searches not using time management (e.g. analysis, fixed node game play etc), bestMoveChanges was not reset during search iterations. As LMR uses this quantity, search was somewhat weaker. Tested using fixed node playing games: ``` ./c-chess-cli -each nodes=10000 option.Hash=16 -engine cmd=../Stockfish/src/fix -engine cmd=../Stockfish/src/master -concurrency 6 -openings file=../books/UHO_XXL_+0.90_+1.19.epd -games 10000 Score of Stockfish Fix vs Stockfish Master: 3187 - 3028 - 3785 [0.508] 10000 ./c-chess-cli -each nodes=30000 option.Hash=16 -engine cmd=../Stockfish/src/fix -engine cmd=../Stockfish/src/master -concurrency 6 -openings file=../books/UHO_XXL_+0.90_+1.19.epd -games 10000 Score of Stockfish Fix vs Stockfish Master: 2946 - 2834 - 4220 [0.506] 10000 ``` closes https://github.com/official-stockfish/Stockfish/pull/3818 bench: 5061979 --- src/search.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 70dc4b21..c926c1d2 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -477,6 +477,13 @@ void Thread::search() { if (skill.enabled() && skill.time_to_pick(rootDepth)) skill.pick_best(multiPV); + // Use part of the gained time from a previous stable move for the current move + for (Thread* th : Threads) + { + totBestMoveChanges += th->bestMoveChanges; + th->bestMoveChanges = 0; + } + // Do we have time for the next iteration? Can we stop searching now? if ( Limits.use_time_management() && !Threads.stop @@ -489,13 +496,6 @@ void Thread::search() { // If the bestMove is stable over several iterations, reduce time accordingly timeReduction = lastBestMoveDepth + 9 < completedDepth ? 1.92 : 0.95; double reduction = (1.47 + mainThread->previousTimeReduction) / (2.32 * timeReduction); - - // Use part of the gained time from a previous stable move for the current move - for (Thread* th : Threads) - { - totBestMoveChanges += th->bestMoveChanges; - th->bestMoveChanges = 0; - } double bestMoveInstability = 1.073 + std::max(1.0, 2.25 - 9.9 / rootDepth) * totBestMoveChanges / Threads.size(); double totalTime = Time.optimum() * fallingEval * reduction * bestMoveInstability; From c9977aa0a89c83bf21651bffd3b6f10c344ccc46 Mon Sep 17 00:00:00 2001 From: Gian-Carlo Pascutto Date: Wed, 1 Dec 2021 23:36:14 +0100 Subject: [PATCH 031/105] Add AVX-VNNI support for Alder Lake and later. In their infinite wisdom, Intel axed AVX512 from Alder Lake chips (well, not entirely, but we kind of want to use the Gracemont cores for chess!) but still added VNNI support. Confusingly enough, this is not the same as VNNI256 support. This adds a specific AVX-VNNI target that will use this AVX-VNNI mode, by prefixing the VNNI instructions with the appropriate VEX prefix, and avoiding AVX512 usage. This is about 1% faster on P cores: Result of 20 runs ================== base (./clang-bmi2 ) = 3306337 +/- 7519 test (./clang-vnni ) = 3344226 +/- 7388 diff = +37889 +/- 4153 speedup = +0.0115 P(speedup > 0) = 1.0000 But a nice 3% faster on E cores: Result of 20 runs ================== base (./clang-bmi2 ) = 1938054 +/- 28257 test (./clang-vnni ) = 1994606 +/- 31756 diff = +56552 +/- 3735 speedup = +0.0292 P(speedup > 0) = 1.0000 This was measured on Clang 13. GCC 11.2 appears to generate worse code for Alder Lake, though the speedup on the E cores is similar. It is possible to run the engine specifically on the P or E using binding, for example in linux it is possible to use (for an 8 P + 8 E setup like i9-12900K): taskset -c 0-15 ./stockfish taskset -c 16-23 ./stockfish where the first call binds to the P-cores and the second to the E-cores. closes https://github.com/official-stockfish/Stockfish/pull/3824 No functional change --- src/Makefile | 26 ++++++++++++++++++++++++-- src/simd.h | 13 ++++++++++--- 2 files changed, 34 insertions(+), 5 deletions(-) diff --git a/src/Makefile b/src/Makefile index 5c52661b..a9333a22 100644 --- a/src/Makefile +++ b/src/Makefile @@ -78,6 +78,7 @@ endif # ssse3 = yes/no --- -mssse3 --- Use Intel Supplemental Streaming SIMD Extensions 3 # sse41 = yes/no --- -msse4.1 --- Use Intel Streaming SIMD Extensions 4.1 # avx2 = yes/no --- -mavx2 --- Use Intel Advanced Vector Extensions 2 +# avxvnni = yes/no --- -mavxvnni --- Use Intel Vector Neural Network Instructions AVX # avx512 = yes/no --- -mavx512bw --- Use Intel Advanced Vector Extensions 512 # vnni256 = yes/no --- -mavx512vnni --- Use Intel Vector Neural Network Instructions 256 # vnni512 = yes/no --- -mavx512vnni --- Use Intel Vector Neural Network Instructions 512 @@ -100,8 +101,8 @@ endif # explicitly check for the list of supported architectures (as listed with make help), # the user can override with `make ARCH=x86-32-vnni256 SUPPORTED_ARCH=true` ifeq ($(ARCH), $(filter $(ARCH), \ - x86-64-vnni512 x86-64-vnni256 x86-64-avx512 x86-64-bmi2 x86-64-avx2 \ - x86-64-sse41-popcnt x86-64-modern x86-64-ssse3 x86-64-sse3-popcnt \ + x86-64-vnni512 x86-64-vnni256 x86-64-avx512 x86-64-avxvnni x86-64-bmi2 \ + x86-64-avx2 x86-64-sse41-popcnt x86-64-modern x86-64-ssse3 x86-64-sse3-popcnt \ x86-64 x86-32-sse41-popcnt x86-32-sse2 x86-32 ppc-64 ppc-32 e2k \ armv7 armv7-neon armv8 apple-silicon general-64 general-32)) SUPPORTED_ARCH=true @@ -122,6 +123,7 @@ sse2 = no ssse3 = no sse41 = no avx2 = no +avxvnni = no avx512 = no vnni256 = no vnni512 = no @@ -192,6 +194,17 @@ ifeq ($(findstring -avx2,$(ARCH)),-avx2) avx2 = yes endif +ifeq ($(findstring -avxvnni,$(ARCH)),-avxvnni) + popcnt = yes + sse = yes + sse2 = yes + ssse3 = yes + sse41 = yes + avx2 = yes + avxvnni = yes + pext = yes +endif + ifeq ($(findstring -bmi2,$(ARCH)),-bmi2) popcnt = yes sse = yes @@ -544,6 +557,13 @@ ifeq ($(avx2),yes) endif endif +ifeq ($(avxvnni),yes) + CXXFLAGS += -DUSE_VNNI -DUSE_AVXVNNI + ifeq ($(comp),$(filter $(comp),gcc clang mingw)) + CXXFLAGS += -mavxvnni + endif +endif + ifeq ($(avx512),yes) CXXFLAGS += -DUSE_AVX512 ifeq ($(comp),$(filter $(comp),gcc clang mingw)) @@ -689,6 +709,7 @@ help: @echo "x86-64-vnni512 > x86 64-bit with vnni support 512bit wide" @echo "x86-64-vnni256 > x86 64-bit with vnni support 256bit wide" @echo "x86-64-avx512 > x86 64-bit with avx512 support" + @echo "x86-64-avxvnni > x86 64-bit with avxvnni support" @echo "x86-64-bmi2 > x86 64-bit with bmi2 support" @echo "x86-64-avx2 > x86 64-bit with avx2 support" @echo "x86-64-sse41-popcnt > x86 64-bit with sse41 and popcnt support" @@ -837,6 +858,7 @@ config-sanity: net @echo "ssse3: '$(ssse3)'" @echo "sse41: '$(sse41)'" @echo "avx2: '$(avx2)'" + @echo "avxvnni: '$(avxvnni)'" @echo "avx512: '$(avx512)'" @echo "vnni256: '$(vnni256)'" @echo "vnni512: '$(vnni512)'" diff --git a/src/simd.h b/src/simd.h index 584148f1..1ac98067 100644 --- a/src/simd.h +++ b/src/simd.h @@ -46,6 +46,13 @@ #define USE_INLINE_ASM #endif +// Use either the AVX512 or AVX-VNNI version of the VNNI instructions. +#if defined(USE_AVXVNNI) +#define VNNI_PREFIX "%{vex%} " +#else +#define VNNI_PREFIX "" +#endif + namespace Stockfish::Simd { #if defined (USE_AVX512) @@ -208,7 +215,7 @@ namespace Stockfish::Simd { # if defined (USE_VNNI) # if defined (USE_INLINE_ASM) asm( - "vpdpbusd %[b], %[a], %[acc]\n\t" + VNNI_PREFIX "vpdpbusd %[b], %[a], %[acc]\n\t" : [acc]"+v"(acc) : [a]"v"(a), [b]"vm"(b) ); @@ -240,8 +247,8 @@ namespace Stockfish::Simd { # if defined (USE_VNNI) # if defined (USE_INLINE_ASM) asm( - "vpdpbusd %[b0], %[a0], %[acc]\n\t" - "vpdpbusd %[b1], %[a1], %[acc]\n\t" + VNNI_PREFIX "vpdpbusd %[b0], %[a0], %[acc]\n\t" + VNNI_PREFIX "vpdpbusd %[b1], %[a1], %[acc]\n\t" : [acc]"+v"(acc) : [a0]"v"(a0), [b0]"vm"(b0), [a1]"v"(a1), [b1]"vm"(b1) ); From e4b7403f127a36a35bbace9f833ab43babd98a6c Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Thu, 2 Dec 2021 23:41:23 +0300 Subject: [PATCH 032/105] Do more aggressive pruning for some node types This patch allows more aggressive futility/see based pruning for PV nodes with low delta and non-pv nodes. Fixes some white space issues. Passed STC https://tests.stockfishchess.org/tests/view/61a5ed33d16c530b5dcc27cc LLR: 2.95 (-2.94,2.94) <0.00,2.50> Total: 182088 W: 47121 L: 46584 D: 88383 Ptnml(0-2): 551, 20687, 48037, 21212, 557 Passed LTC https://tests.stockfishchess.org/tests/view/61a74dfdbd5c4360bcded0ac LLR: 2.94 (-2.94,2.94) <0.50,3.00> Total: 87136 W: 22494 L: 22103 D: 42539 Ptnml(0-2): 38, 8918, 25272, 9295, 45 closes https://github.com/official-stockfish/Stockfish/pull/3828 closes https://github.com/official-stockfish/Stockfish/pull/3829 bench 4332259 --- src/misc.cpp | 8 ++++---- src/misc.h | 2 +- src/search.cpp | 2 ++ 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/src/misc.cpp b/src/misc.cpp index 294b7c8f..b46786df 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -515,7 +515,7 @@ int best_node(size_t idx) { if (!fun1) return -1; - // First call to GetLogicalProcessorInformationEx() to get returnLength. + // First call to GetLogicalProcessorInformationEx() to get returnLength. // We expect the call to fail due to null buffer. if (fun1(RelationAll, nullptr, &returnLength)) return -1; @@ -589,13 +589,13 @@ void bindThisThread(size_t idx) { if (!fun2 || !fun3) return; - if (!fun4 || !fun5) + if (!fun4 || !fun5) { GROUP_AFFINITY affinity; if (fun2(node, &affinity)) // GetNumaNodeProcessorMaskEx fun3(GetCurrentThread(), &affinity, nullptr); // SetThreadGroupAffinity - } - else + } + else { // If a numa node has more than one processor group, we assume they are // sized equal and we spread threads evenly across the groups. diff --git a/src/misc.h b/src/misc.h index c1744130..062b420a 100644 --- a/src/misc.h +++ b/src/misc.h @@ -141,7 +141,7 @@ private: /// sigmoid(t, x0, y0, C, P, Q) implements a sigmoid-like function using only integers, /// with the following properties: -/// +/// /// - sigmoid is centered in (x0, y0) /// - sigmoid has amplitude [-P/Q , P/Q] instead of [-1 , +1] /// - limit is (y0 - P/Q) when t tends to -infinity diff --git a/src/search.cpp b/src/search.cpp index c926c1d2..5e022e66 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1065,6 +1065,8 @@ moves_loop: // When in check, search starts here history += thisThread->mainHistory[us][from_to(move)]; + lmrDepth = std::max(0, lmrDepth - (beta - alpha < thisThread->rootDelta / 4)); + // Futility pruning: parent node (~5 Elo) if ( !ss->inCheck && lmrDepth < 8 From 327060232a3ded6ed19113f234a2f9ba9bf65b02 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Thu, 2 Dec 2021 06:58:40 +0100 Subject: [PATCH 033/105] Update default net to nn-cdf1785602d6.nnue Same process as in https://github.com/official-stockfish/Stockfish/commit/e4a0c6c75950bf27b6dc32490a1102499643126b with the training started from the current master net. passed STC: LLR: 2.95 (-2.94,2.94) <0.00,2.50> Total: 38224 W: 10023 L: 9742 D: 18459 Ptnml(0-2): 133, 4328, 9940, 4547, 164 https://tests.stockfishchess.org/tests/view/61a8611e4ed77d629d4e836e passed LTC: LLR: 2.94 (-2.94,2.94) <0.50,3.00> Total: 115176 W: 29783 L: 29321 D: 56072 Ptnml(0-2): 68, 12039, 32936, 12453, 92 https://tests.stockfishchess.org/tests/view/61a8963e4ed77d629d4e8d9b closes https://github.com/official-stockfish/Stockfish/pull/3830 Bench: 4829419 --- src/evaluate.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/evaluate.h b/src/evaluate.h index 77c3b4e7..873a72dc 100644 --- a/src/evaluate.h +++ b/src/evaluate.h @@ -39,7 +39,7 @@ namespace Eval { // The default net name MUST follow the format nn-[SHA256 first 12 digits].nnue // for the build process (profile-build and fishtest) to work. Do not change the // name of the macro, as it is used in the Makefile. - #define EvalFileDefaultName "nn-4f56ecfca5b7.nnue" + #define EvalFileDefaultName "nn-cdf1785602d6.nnue" namespace NNUE { From a6a9d828ab4cc35ca0f64207e2ff818a391d1939 Mon Sep 17 00:00:00 2001 From: bmc4 Date: Sat, 4 Dec 2021 09:09:09 -0300 Subject: [PATCH 034/105] Simplifies bestMoveChanges from LMR As bestMoveChanges is only reset on mainThread and it could change how other threads search, a multi-threads test was made. STC: LLR: 2.94 (-2.94,2.94) <-2.25,0.25> Total: 146776 W: 37934 L: 37941 D: 70901 Ptnml(0-2): 477, 15644, 41173, 15597, 497 https://tests.stockfishchess.org/tests/view/61a8f9f34ed77d629d4ea2d6 LTC: LLR: 3.11 (-2.94,2.94) <-2.25,0.25> Total: 114040 W: 29314 L: 29269 D: 55457 Ptnml(0-2): 50, 10584, 35722, 10599, 65 https://tests.stockfishchess.org/tests/view/61a9d4bf9e8855bba1a35c4f (SMP, 8 threads) STC: LLR: 2.95 (-2.94,2.94) <-2.25,0.25> Total: 23888 W: 6308 L: 6143 D: 11437 Ptnml(0-2): 36, 2557, 6600, 2708, 43 https://tests.stockfishchess.org/tests/view/61ac27a756fcf33bce7d3677 closes https://github.com/official-stockfish/Stockfish/pull/3831 bench: 4829419 --- src/search.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 5e022e66..28e16609 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1187,9 +1187,8 @@ moves_loop: // When in check, search starts here && !likelyFailLow) r -= 2; - // Increase reduction at non-PV nodes when the best move does not change frequently - if ( !PvNode - && thisThread->bestMoveChanges <= 2) + // Increase reduction at non-PV nodes + if (!PvNode) r++; // Decrease reduction if opponent's move count is high (~1 Elo) From 18f2b12cd019212b9c7103cc63e3bf64a5be7c3c Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Sun, 5 Dec 2021 16:18:33 +0100 Subject: [PATCH 035/105] Tweak time management Use for adjustment of the falling eval time factor now also the difference between previous best average score and current best score. STC: LLR: 2.95 (-2.94,2.94) <0.00,2.50> Total: 109216 W: 28296 L: 27900 D: 53020 Ptnml(0-2): 312, 11759, 30148, 11999, 390 https://tests.stockfishchess.org/tests/view/61aafa8d1b31b85bcfa29d9c LTC: LLR: 2.93 (-2.94,2.94) <0.50,3.00> Total: 54096 W: 14091 L: 13787 D: 26218 Ptnml(0-2): 29, 5124, 16447, 5410, 38 https://tests.stockfishchess.org/tests/view/61abbbbd56fcf33bce7d1d64 closes https://github.com/official-stockfish/Stockfish/pull/3833 Bench: 4829419 --- src/search.cpp | 4 +++- src/thread.cpp | 1 + src/thread.h | 1 + 3 files changed, 5 insertions(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 28e16609..99c47431 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -260,6 +260,7 @@ void MainThread::search() { bestThread = Threads.get_best_thread(); bestPreviousScore = bestThread->rootMoves[0].score; + bestPreviousAverageScore = bestThread->rootMoves[0].averageScore; // Send again PV info if we have a new best thread if (bestThread != this) @@ -489,7 +490,8 @@ void Thread::search() { && !Threads.stop && !mainThread->stopOnPonderhit) { - double fallingEval = (318 + 6 * (mainThread->bestPreviousScore - bestValue) + double fallingEval = (142 + 6 * (mainThread->bestPreviousScore - bestValue) + + 6 * (mainThread->bestPreviousAverageScore - bestValue) + 6 * (mainThread->iterValue[iterIdx] - bestValue)) / 825.0; fallingEval = std::clamp(fallingEval, 0.5, 1.5); diff --git a/src/thread.cpp b/src/thread.cpp index da8e1d05..c03079d1 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -162,6 +162,7 @@ void ThreadPool::clear() { main()->callsCnt = 0; main()->bestPreviousScore = VALUE_INFINITE; + main()->bestPreviousAverageScore = VALUE_INFINITE; main()->previousTimeReduction = 1.0; } diff --git a/src/thread.h b/src/thread.h index cd206faa..37c6452b 100644 --- a/src/thread.h +++ b/src/thread.h @@ -95,6 +95,7 @@ struct MainThread : public Thread { double previousTimeReduction; Value bestPreviousScore; + Value bestPreviousAverageScore; Value iterValue[4]; int callsCnt; bool stopOnPonderhit; From 7d44b43b3ceb2eebc756709432a0e291f885a1d2 Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Sun, 5 Dec 2021 16:29:51 +0100 Subject: [PATCH 036/105] Tweak history initialization Initialize continuation history with a slighlty negative value -71 instead of zero. The idea is, because the most history entries will be later negative anyway, to shift the starting values a little bit in the "correct" direction. Of course the effect of initialization dimishes with greater depth so I had the apprehension that the LTC test would be difficult to pass, but it passed. STC: LLR: 2.94 (-2.94,2.94) <0.00,2.50> Total: 34520 W: 9076 L: 8803 D: 16641 Ptnml(0-2): 136, 3837, 9047, 4098, 142 https://tests.stockfishchess.org/tests/view/61aa52e39e8855bba1a3776b LTC: LLR: 2.93 (-2.94,2.94) <0.50,3.00> Total: 75568 W: 19620 L: 19254 D: 36694 Ptnml(0-2): 44, 7773, 21796, 8115, 56 https://tests.stockfishchess.org/tests/view/61aa87d39e8855bba1a383a5 closes https://github.com/official-stockfish/Stockfish/pull/3834 Bench: 4674029 --- src/thread.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/thread.cpp b/src/thread.cpp index c03079d1..ed3accc5 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -67,7 +67,7 @@ void Thread::clear() { { for (auto& to : continuationHistory[inCheck][c]) for (auto& h : to) - h->fill(0); + h->fill(-71); continuationHistory[inCheck][c][NO_PIECE][0]->fill(Search::CounterMovePruneThreshold - 1); } } From a3d425cf55494a4f86dc52a3d3b24c1657cbbc61 Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Mon, 6 Dec 2021 03:52:44 +0300 Subject: [PATCH 037/105] Assign extra bonus for previous move that caused a fail low more often This patch allows to assign extra bonus for previous move that caused a fail low not only for PvNodes and cutNodes but also fo some allNodes - namely if the best result we could've got from the search is still far below alpha. passed STC https://tests.stockfishchess.org/tests/view/61aa26a49e8855bba1a36d96 LLR: 2.94 (-2.94,2.94) <0.00,2.50> Total: 73808 W: 19183 L: 18842 D: 35783 Ptnml(0-2): 251, 8257, 19564, 8564, 268 passed LTC https://tests.stockfishchess.org/tests/view/61aa7dc29e8855bba1a3814f LLR: 2.94 (-2.94,2.94) <0.50,3.00> Total: 142416 W: 36717 L: 36192 D: 69507 Ptnml(0-2): 106, 14799, 40862, 15346, 95 closes https://github.com/official-stockfish/Stockfish/pull/3835 bench 4724181 --- src/search.cpp | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 99c47431..edeed9c0 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1380,7 +1380,15 @@ moves_loop: // When in check, search starts here // Bonus for prior countermove that caused the fail low else if ( (depth >= 3 || PvNode) && !priorCapture) - update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, stat_bonus(depth) * (1 + (PvNode || cutNode))); + { + //Assign extra bonus if current node is PvNode or cutNode + //or fail low was really bad + bool extraBonus = PvNode + || cutNode + || bestValue < alpha - 94 * depth; + + update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, stat_bonus(depth) * (1 + extraBonus)); + } if (PvNode) bestValue = std::min(bestValue, maxValue); From b82d93ece484f833c994b40d9eddd959ba20ef92 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Sat, 4 Dec 2021 23:18:46 +0100 Subject: [PATCH 038/105] Update default net to nn-63376713ba63.nnue. same data set as previous trained nets, tuned the wdl model slightly for training. https://github.com/vondele/nnue-pytorch/tree/wdlTweak1 passed STC: https://tests.stockfishchess.org/tests/view/61abe9e456fcf33bce7d2834 LLR: 2.93 (-2.94,2.94) <0.00,2.50> Total: 31720 W: 8385 L: 8119 D: 15216 Ptnml(0-2): 117, 3534, 8273, 3838, 98 passed LTC: https://tests.stockfishchess.org/tests/view/61ac293756fcf33bce7d36cf LLR: 2.96 (-2.94,2.94) <0.50,3.00> Total: 136136 W: 35255 L: 34741 D: 66140 Ptnml(0-2): 114, 14217, 38894, 14727, 116 closes https://github.com/official-stockfish/Stockfish/pull/3836 Bench: 4667742 --- src/evaluate.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/evaluate.h b/src/evaluate.h index 873a72dc..87cb65f3 100644 --- a/src/evaluate.h +++ b/src/evaluate.h @@ -39,7 +39,7 @@ namespace Eval { // The default net name MUST follow the format nn-[SHA256 first 12 digits].nnue // for the build process (profile-build and fishtest) to work. Do not change the // name of the macro, as it is used in the Makefile. - #define EvalFileDefaultName "nn-cdf1785602d6.nnue" + #define EvalFileDefaultName "nn-63376713ba63.nnue" namespace NNUE { From 4766dfc3956f78d853c5e0c4636d6f90fd93df9a Mon Sep 17 00:00:00 2001 From: Tomasz Sobczyk Date: Thu, 2 Dec 2021 12:29:11 +0100 Subject: [PATCH 039/105] Optimize FT activation and affine transform for NEON. This patch optimizes the NEON implementation in two ways. The activation layer after the feature transformer is rewritten to make it easier for the compiler to see through dependencies and unroll. This in itself is a minimal, but a positive improvement. Other architectures could benefit from this too in the future. This is not an algorithmic change. The affine transform for large matrices (first layer after FT) on NEON now utilizes the same optimized code path as >=SSSE3, which makes the memory accesses more sequential and makes better use of the available registers, which allows for code that has longer dependency chains. Benchmarks from Redshift#161, profile-build with apple clang george@Georges-MacBook-Air nets % ./stockfish-b82d93 bench 2>&1 | tail -4 (current master) =========================== Total time (ms) : 2167 Nodes searched : 4667742 Nodes/second : 2154011 george@Georges-MacBook-Air nets % ./stockfish-7377b8 bench 2>&1 | tail -4 (this patch) =========================== Total time (ms) : 1842 Nodes searched : 4667742 Nodes/second : 2534061 This is a solid 18% improvement overall, larger in a bench with NNUE-only, not mixed. Improvement is also observed on armv7-neon (Raspberry Pi, and older phones), around 5% speedup. No changes for architectures other than NEON. closes https://github.com/official-stockfish/Stockfish/pull/3837 No functional changes. --- src/Makefile | 8 +++- src/nnue/layers/affine_transform.h | 64 +++++++++++++++++------------ src/nnue/nnue_feature_transformer.h | 13 ++++-- src/simd.h | 39 ++++++++++++++++++ 4 files changed, 94 insertions(+), 30 deletions(-) diff --git a/src/Makefile b/src/Makefile index a9333a22..3cf97873 100644 --- a/src/Makefile +++ b/src/Makefile @@ -128,6 +128,7 @@ avx512 = no vnni256 = no vnni512 = no neon = no +arm_version = 0 STRIP = strip ### 2.2 Architecture specific @@ -275,6 +276,7 @@ ifeq ($(ARCH),armv7) arch = armv7 prefetch = yes bits = 32 + arm_version = 7 endif ifeq ($(ARCH),armv7-neon) @@ -283,6 +285,7 @@ ifeq ($(ARCH),armv7-neon) popcnt = yes neon = yes bits = 32 + arm_version = 7 endif ifeq ($(ARCH),armv8) @@ -290,6 +293,7 @@ ifeq ($(ARCH),armv8) prefetch = yes popcnt = yes neon = yes + arm_version = 8 endif ifeq ($(ARCH),apple-silicon) @@ -297,6 +301,7 @@ ifeq ($(ARCH),apple-silicon) prefetch = yes popcnt = yes neon = yes + arm_version = 8 endif ifeq ($(ARCH),ppc-32) @@ -614,7 +619,7 @@ ifeq ($(mmx),yes) endif ifeq ($(neon),yes) - CXXFLAGS += -DUSE_NEON + CXXFLAGS += -DUSE_NEON=$(arm_version) ifeq ($(KERNEL),Linux) ifneq ($(COMP),ndk) ifneq ($(arch),armv8) @@ -863,6 +868,7 @@ config-sanity: net @echo "vnni256: '$(vnni256)'" @echo "vnni512: '$(vnni512)'" @echo "neon: '$(neon)'" + @echo "arm_version: '$(arm_version)'" @echo "" @echo "Flags:" @echo "CXX: $(CXX)" diff --git a/src/nnue/layers/affine_transform.h b/src/nnue/layers/affine_transform.h index b2871278..11038d69 100644 --- a/src/nnue/layers/affine_transform.h +++ b/src/nnue/layers/affine_transform.h @@ -75,8 +75,7 @@ namespace Stockfish::Eval::NNUE::Layers { const auto inputVector = reinterpret_cast(input); # elif defined(USE_NEON) - static_assert(PaddedInputDimensions % 16 == 0); - constexpr IndexType NumChunks = PaddedInputDimensions / 16; + constexpr IndexType NumChunks = (InputDimensions + 15) / 16; const auto inputVector = reinterpret_cast(input); # endif @@ -181,6 +180,9 @@ namespace Stockfish::Eval::NNUE::Layers { #elif defined (USE_SSSE3) static constexpr const IndexType InputSimdWidth = 16; static constexpr const IndexType MaxNumOutputRegs = 8; +#elif defined (USE_NEON) + static constexpr const IndexType InputSimdWidth = 8; + static constexpr const IndexType MaxNumOutputRegs = 8; #else // The fallback implementation will not have permuted weights. // We define these to avoid a lot of ifdefs later. @@ -270,52 +272,64 @@ namespace Stockfish::Eval::NNUE::Layers { OutputType* output = reinterpret_cast(buffer); #if defined (USE_AVX512) - using vec_t = __m512i; - #define vec_setzero _mm512_setzero_si512 - #define vec_set_32 _mm512_set1_epi32 - #define vec_add_dpbusd_32 Simd::m512_add_dpbusd_epi32 + using acc_vec_t = __m512i; + using bias_vec_t = __m128i; + using weight_vec_t = __m512i; + using in_vec_t = __m512i; + #define vec_zero _mm512_setzero_si512() #define vec_add_dpbusd_32x2 Simd::m512_add_dpbusd_epi32x2 #define vec_hadd Simd::m512_hadd #define vec_haddx4 Simd::m512_haddx4 #elif defined (USE_AVX2) - using vec_t = __m256i; - #define vec_setzero _mm256_setzero_si256 - #define vec_set_32 _mm256_set1_epi32 - #define vec_add_dpbusd_32 Simd::m256_add_dpbusd_epi32 + using acc_vec_t = __m256i; + using bias_vec_t = __m128i; + using weight_vec_t = __m256i; + using in_vec_t = __m256i; + #define vec_zero _mm256_setzero_si256() #define vec_add_dpbusd_32x2 Simd::m256_add_dpbusd_epi32x2 #define vec_hadd Simd::m256_hadd #define vec_haddx4 Simd::m256_haddx4 #elif defined (USE_SSSE3) - using vec_t = __m128i; - #define vec_setzero _mm_setzero_si128 - #define vec_set_32 _mm_set1_epi32 - #define vec_add_dpbusd_32 Simd::m128_add_dpbusd_epi32 + using acc_vec_t = __m128i; + using bias_vec_t = __m128i; + using weight_vec_t = __m128i; + using in_vec_t = __m128i; + #define vec_zero _mm_setzero_si128() #define vec_add_dpbusd_32x2 Simd::m128_add_dpbusd_epi32x2 #define vec_hadd Simd::m128_hadd #define vec_haddx4 Simd::m128_haddx4 +#elif defined (USE_NEON) + using acc_vec_t = int32x4_t; + using bias_vec_t = int32x4_t; + using weight_vec_t = int8x8_t; + using in_vec_t = int8x8_t; + #define vec_zero {0} + #define vec_add_dpbusd_32x2 Simd::neon_m128_add_dpbusd_epi32x2 + #define vec_hadd Simd::neon_m128_hadd + #define vec_haddx4 Simd::neon_m128_haddx4 #endif -#if defined (USE_SSSE3) - const vec_t* invec = reinterpret_cast(input); +#if defined (USE_SSSE3) || defined (USE_NEON) + const in_vec_t* invec = reinterpret_cast(input); // Perform accumulation to registers for each big block for (IndexType bigBlock = 0; bigBlock < NumBigBlocks; ++bigBlock) { - vec_t acc[NumOutputRegs] = { vec_setzero() }; + acc_vec_t acc[NumOutputRegs] = { vec_zero }; // Each big block has NumOutputRegs small blocks in each "row", one per register. // We process two small blocks at a time to save on one addition without VNNI. for (IndexType smallBlock = 0; smallBlock < NumSmallBlocksPerOutput; smallBlock += 2) { - const vec_t* weightvec = - reinterpret_cast( + const weight_vec_t* weightvec = + reinterpret_cast( weights + bigBlock * BigBlockSize + smallBlock * SmallBlockSize * NumOutputRegs); - const vec_t in0 = invec[smallBlock + 0]; - const vec_t in1 = invec[smallBlock + 1]; + const in_vec_t in0 = invec[smallBlock + 0]; + const in_vec_t in1 = invec[smallBlock + 1]; for (IndexType k = 0; k < NumOutputRegs; ++k) vec_add_dpbusd_32x2(acc[k], in0, weightvec[k], in1, weightvec[k + NumOutputRegs]); @@ -324,8 +338,8 @@ namespace Stockfish::Eval::NNUE::Layers { // Horizontally add all accumulators. if constexpr (NumOutputRegs % 4 == 0) { - __m128i* outputvec = reinterpret_cast<__m128i*>(output); - const __m128i* biasvec = reinterpret_cast(biases); + bias_vec_t* outputvec = reinterpret_cast(output); + const bias_vec_t* biasvec = reinterpret_cast(biases); for (IndexType k = 0; k < NumOutputRegs; k += 4) { @@ -343,9 +357,7 @@ namespace Stockfish::Eval::NNUE::Layers { } } -# undef vec_setzero -# undef vec_set_32 -# undef vec_add_dpbusd_32 +# undef vec_zero # undef vec_add_dpbusd_32x2 # undef vec_hadd # undef vec_haddx4 diff --git a/src/nnue/nnue_feature_transformer.h b/src/nnue/nnue_feature_transformer.h index 0297b323..4f6a174a 100644 --- a/src/nnue/nnue_feature_transformer.h +++ b/src/nnue/nnue_feature_transformer.h @@ -336,10 +336,17 @@ namespace Stockfish::Eval::NNUE { { const IndexType offset = HalfDimensions * p; const auto out = reinterpret_cast(&output[offset]); - for (IndexType j = 0; j < NumChunks; ++j) + + constexpr IndexType UnrollFactor = 16; + static_assert(UnrollFactor % UnrollFactor == 0); + for (IndexType j = 0; j < NumChunks; j += UnrollFactor) { - int16x8_t sum = reinterpret_cast(accumulation[perspectives[p]])[j]; - out[j] = vmax_s8(vqmovn_s16(sum), Zero); + int16x8_t sums[UnrollFactor]; + for (IndexType i = 0; i < UnrollFactor; ++i) + sums[i] = reinterpret_cast(accumulation[perspectives[p]])[j+i]; + + for (IndexType i = 0; i < UnrollFactor; ++i) + out[j+i] = vmax_s8(vqmovn_s16(sums[i]), Zero); } } return psqt; diff --git a/src/simd.h b/src/simd.h index 1ac98067..ffa54d96 100644 --- a/src/simd.h +++ b/src/simd.h @@ -343,6 +343,45 @@ namespace Stockfish::Simd { #endif +#if defined (USE_NEON) + + [[maybe_unused]] static int neon_m128_reduce_add_epi32(int32x4_t s) { +# if USE_NEON >= 8 + return vaddvq_s32(s); +# else + return s[0] + s[1] + s[2] + s[3]; +# endif + } + + [[maybe_unused]] static int neon_m128_hadd(int32x4_t sum, int bias) { + return neon_m128_reduce_add_epi32(sum) + bias; + } + + [[maybe_unused]] static int32x4_t neon_m128_haddx4( + int32x4_t sum0, int32x4_t sum1, int32x4_t sum2, int32x4_t sum3, + int32x4_t bias) { + + int32x4_t hsums { + neon_m128_reduce_add_epi32(sum0), + neon_m128_reduce_add_epi32(sum1), + neon_m128_reduce_add_epi32(sum2), + neon_m128_reduce_add_epi32(sum3) + }; + return vaddq_s32(hsums, bias); + } + + [[maybe_unused]] static void neon_m128_add_dpbusd_epi32x2( + int32x4_t& acc, + int8x8_t a0, int8x8_t b0, + int8x8_t a1, int8x8_t b1) { + + int16x8_t product = vmull_s8(a0, b0); + product = vmlal_s8(product, a1, b1); + acc = vpadalq_s16(acc, product); + } + +#endif + } #endif // STOCKFISH_SIMD_H_INCLUDED From c228f3196ae9965250f317c8784012c2485228c4 Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Tue, 7 Dec 2021 19:46:21 +0300 Subject: [PATCH 040/105] Introduce post-lmr extensions This idea is somewhat similar to extentions in LMR but has a different flavour. If result of LMR was really good - thus exceeded alpha by some pretty big given margin, we can extend move after LMR in full depth search with 0 window. The idea is that this move is probably a fail high with somewhat of a big probability so extending it makes a lot of sense passed STC https://tests.stockfishchess.org/tests/view/61ad45ea56fcf33bce7d74b7 LLR: 2.94 (-2.94,2.94) <0.00,2.50> Total: 59680 W: 15531 L: 15215 D: 28934 Ptnml(0-2): 193, 6711, 15734, 6991, 211 passed LTC https://tests.stockfishchess.org/tests/view/61ad9ff356fcf33bce7d8646 LLR: 2.95 (-2.94,2.94) <0.50,3.00> Total: 59104 W: 15321 L: 14992 D: 28791 Ptnml(0-2): 53, 6023, 17065, 6364, 47 closes https://github.com/official-stockfish/Stockfish/pull/3838 bench 4881329 --- src/search.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index edeed9c0..f3a96ae2 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1165,6 +1165,8 @@ moves_loop: // When in check, search starts here // Step 15. Make the move pos.do_move(move, st, givesCheck); + bool doDeeperSearch = false; + // Step 16. Late moves reduction / extension (LMR, ~200 Elo) // We use various heuristics for the sons of a node after the first son has // been searched. In general we would like to reduce them, but there are many @@ -1237,6 +1239,7 @@ moves_loop: // When in check, search starts here // If the son is reduced and fails high it will be re-searched at full depth doFullDepthSearch = value > alpha && d < newDepth; + doDeeperSearch = value > alpha + 88; didLMR = true; } else @@ -1248,7 +1251,7 @@ moves_loop: // When in check, search starts here // Step 17. Full depth search when LMR is skipped or fails high if (doFullDepthSearch) { - value = -search(pos, ss+1, -(alpha+1), -alpha, newDepth, !cutNode); + value = -search(pos, ss+1, -(alpha+1), -alpha, newDepth + doDeeperSearch, !cutNode); // If the move passed LMR update its stats if (didLMR && !captureOrPromotion) From 94514199123874c0029afb6e00634f26741d90db Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Wed, 8 Dec 2021 12:23:39 +0100 Subject: [PATCH 041/105] Improve transposition table remplacement strategy Increase chance that PV node replaces old entry in transposition table. STC: LLR: 2.93 (-2.94,2.94) <0.00,2.50> Total: 46744 W: 12108 L: 11816 D: 22820 Ptnml(0-2): 156, 5221, 12344, 5477, 174 https://tests.stockfishchess.org/tests/view/61ae068356fcf33bce7d99d0 LTC: LLR: 2.94 (-2.94,2.94) <0.50,3.00> Total: 88464 W: 22912 L: 22513 D: 43039 Ptnml(0-2): 84, 9133, 25393, 9544, 78 https://tests.stockfishchess.org/tests/view/61ae973656fcf33bce7db3e1 closes https://github.com/official-stockfish/Stockfish/pull/3839 Bench: 5292488 --- src/tt.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tt.cpp b/src/tt.cpp index 1f495ca9..4af6c9f1 100644 --- a/src/tt.cpp +++ b/src/tt.cpp @@ -40,9 +40,9 @@ void TTEntry::save(Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev) move16 = (uint16_t)m; // Overwrite less valuable entries (cheapest checks first) - if (b == BOUND_EXACT + if ( b == BOUND_EXACT || (uint16_t)k != key16 - || d - DEPTH_OFFSET > depth8 - 4) + || d - DEPTH_OFFSET + 2 * pv > depth8 - 4) { assert(d > DEPTH_OFFSET); assert(d < 256 + DEPTH_OFFSET); From 8e8234593190804babd36b8a8862e2bb1fc65bb7 Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Thu, 9 Dec 2021 19:33:06 +0300 Subject: [PATCH 042/105] Adjust singular extension depth restriction This patch is a modification of original idea by lonfom169 which had a good yellow run - do singular extension search with depth threshold 6 unless this is a PvNode with is a part of a PV line - for them set threshold to 8 instead. Passed STC https://tests.stockfishchess.org/tests/view/61b1080406b4c2dcb1b1128c LLR: 2.95 (-2.94,2.94) <0.00,2.50> Total: 84352 W: 21917 L: 21555 D: 40880 Ptnml(0-2): 288, 9524, 22185, 9896, 283 Passed LTC https://tests.stockfishchess.org/tests/view/61b1860a06b4c2dcb1b134a1 LLR: 2.95 (-2.94,2.94) <0.50,3.00> Total: 63520 W: 16575 L: 16237 D: 30708 Ptnml(0-2): 27, 6519, 18350, 6817, 47 https://github.com/official-stockfish/Stockfish/pull/3840 bench 4729473 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index f3a96ae2..cded8614 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1089,7 +1089,7 @@ moves_loop: // When in check, search starts here // a reduced search on all the other moves but the ttMove and if the // result is lower than ttValue minus a margin, then we will extend the ttMove. if ( !rootNode - && depth >= 7 + && depth >= 6 + 2 * (PvNode && tte->is_pv()) && move == ttMove && !excludedMove // Avoid recursive singular search /* && ttValue != VALUE_NONE Already implicit in the next condition */ From 9db6ca8592c2c372cc28d8c463dd9eeca464e893 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Sat, 11 Dec 2021 15:23:55 +0100 Subject: [PATCH 043/105] Update Top CPU Contributors closes https://github.com/official-stockfish/Stockfish/pull/3842 No functional change --- Top CPU Contributors.txt | 424 ++++++++++++++++++++------------------- 1 file changed, 221 insertions(+), 203 deletions(-) diff --git a/Top CPU Contributors.txt b/Top CPU Contributors.txt index dacc5781..f0ec51f9 100644 --- a/Top CPU Contributors.txt +++ b/Top CPU Contributors.txt @@ -1,205 +1,223 @@ -Contributors to Fishtest with >10,000 CPU hours, as of Jun 29, 2021. +Contributors to Fishtest with >10,000 CPU hours, as of 2021-12-11. Thank you! -Username CPU Hours Games played ------------------------------------------------------ -noobpwnftw 27649494 1834734733 -mlang 1426107 89454622 -dew 1380910 82831648 -mibere 703840 46867607 -grandphish2 692707 41737913 -tvijlbrief 669642 42371594 -JojoM 597778 35297180 -TueRens 519226 31823562 -cw 458421 30307421 -fastgm 439667 25950040 -gvreuls 436599 28177460 -crunchy 427035 27344275 -CSU_Dynasty 374765 25106278 -Fisherman 326901 21822979 -ctoks 325477 21767943 -velislav 295343 18844324 -linrock 292789 10624427 -bcross 278584 19488961 -okrout 262818 13803272 -pemo 245982 11376085 -glinscott 217799 13780820 -leszek 212346 12959025 -nordlandia 211692 13484886 -bking_US 198894 11876016 -drabel 196463 13450602 -robal 195473 12375650 -mgrabiak 187226 12016564 -Dantist 183202 10990484 -Thanar 179852 12365359 -vdv 175274 9889046 -spams 157128 10319326 -marrco 150295 9402141 -sqrt2 147963 9724586 -mhoram 141278 8901241 -CoffeeOne 137100 5024116 -vdbergh 137041 8926915 -malala 136182 8002293 -xoto 133702 9156676 -davar 122092 7960001 -dsmith 122059 7570238 -Data 113305 8220352 -BrunoBanani 112960 7436849 -MaZePallas 102823 6633619 -sterni1971 100532 5880772 -ElbertoOne 99028 7023771 -brabos 92118 6186135 -oz 92100 6486640 -psk 89957 5984901 -amicic 89156 5392305 -sunu 88851 6028873 -Vizvezdenec 83761 5344740 -0x3C33 82614 5271253 -BRAVONE 81239 5054681 -racerschmacer 80899 5759262 -cuistot 80300 4606144 -nssy 76497 5259388 -teddybaer 75125 5407666 -Pking_cda 73776 5293873 -jromang 72192 5057715 -solarlight 70517 5028306 -dv8silencer 70287 3883992 -Bobo1239 68515 4652287 -manap 66273 4121774 -skiminki 65088 4023328 -tinker 64333 4268790 -sschnee 60767 3500800 -qurashee 57344 3168264 -robnjr 57262 4053117 -Freja 56938 3733019 -ttruscott 56010 3680085 -rkl 55132 4164467 -renouve 53811 3501516 -finfish 51360 3370515 -eva42 51272 3599691 -rap 49985 3219146 -pb00067 49727 3298270 -ronaldjerum 47654 3240695 -bigpen0r 47653 3335327 -eastorwest 47585 3221629 -biffhero 46564 3111352 -VoyagerOne 45476 3452465 -yurikvelo 44834 3034550 -speedycpu 43842 3003273 -jbwiebe 43305 2805433 -Spprtr 42279 2680153 -DesolatedDodo 42007 2447516 -Antihistamine 41788 2761312 -mhunt 41735 2691355 -homyur 39893 2850481 -gri 39871 2515779 -Fifis 38776 2529121 -oryx 38724 2966648 -SC 37290 2731014 -csnodgrass 36207 2688994 -jmdana 36157 2210661 -strelock 34716 2074055 -rpngn 33951 2057395 -Garf 33922 2751802 -EthanOConnor 33370 2090311 -slakovv 32915 2021889 -manapbk 30987 1810399 -Prcuvu 30377 2170122 -anst 30301 2190091 -jkiiski 30136 1904470 -hyperbolic.tom 29840 2017394 -Pyafue 29650 1902349 -Wolfgang 29260 1658936 -zeryl 28156 1579911 -OuaisBla 27636 1578800 -DMBK 27051 1999456 -chriswk 26902 1868317 -achambord 26582 1767323 -Patrick_G 26276 1801617 -yorkman 26193 1992080 -SFTUser 25182 1675689 -nabildanial 24942 1519409 -Sharaf_DG 24765 1786697 -ncfish1 24411 1520927 -rodneyc 24227 1409514 -agg177 23890 1395014 -JanErik 23408 1703875 -Isidor 23388 1680691 -Norabor 23164 1591830 -cisco2015 22897 1762669 -Zirie 22542 1472937 -team-oh 22272 1636708 -MazeOfGalious 21978 1629593 -sg4032 21947 1643265 -ianh2105 21725 1632562 -xor12 21628 1680365 -dex 21612 1467203 -nesoneg 21494 1463031 -sphinx 21211 1384728 -jjoshua2 21001 1423089 -horst.prack 20878 1465656 -Ente 20865 1477066 -0xB00B1ES 20590 1208666 -j3corre 20405 941444 -Adrian.Schmidt123 20316 1281436 -wei 19973 1745989 -MaxKlaxxMiner 19850 1009176 -rstoesser 19569 1293588 -gopeto 19491 1174952 -eudhan 19274 1283717 -jundery 18445 1115855 -megaman7de 18377 1067540 -iisiraider 18247 1101015 -ville 17883 1384026 -chris 17698 1487385 -purplefishies 17595 1092533 -dju 17353 978595 -DragonLord 17014 1162790 -IgorLeMasson 16064 1147232 -ako027ako 15671 1173203 -chuckstablers 15289 891576 -Nikolay.IT 15154 1068349 -Andrew Grant 15114 895539 -OssumOpossum 14857 1007129 -Karby 14808 867120 -enedene 14476 905279 -bpfliegel 14298 884523 -mpx86 14019 759568 -jpulman 13982 870599 -crocogoat 13803 1117422 -joster 13794 950160 -Nesa92 13786 1114691 -Hjax 13535 915487 -jsys14 13459 785000 -Dark_wizzie 13422 1007152 -mabichito 12903 749391 -thijsk 12886 722107 -AdrianSA 12860 804972 -Flopzee 12698 894821 -fatmurphy 12547 853210 -Rudolphous 12520 832340 -scuzzi 12511 845761 -SapphireBrand 12416 969604 -modolief 12386 896470 -Machariel 12335 810784 -pgontarz 12151 848794 -stocky 11954 699440 -mschmidt 11941 803401 -Maxim 11543 836024 -infinity 11470 727027 -torbjo 11395 729145 -Thomas A. Anderson 11372 732094 -savage84 11358 670860 -d64 11263 789184 -MooTheCow 11237 720174 -snicolet 11106 869170 -ali-al-zhrani 11086 767926 -AndreasKrug 10875 887457 -pirt 10806 836519 -basepi 10637 744851 -michaelrpg 10508 739039 -dzjp 10343 732529 -aga 10302 622975 -ols 10259 570669 -lbraesch 10252 647825 -FormazChar 10059 757283 +Username CPU Hours Games played +------------------------------------------------------------------ +noobpwnftw 29832955 2061725095 +mlang 2345848 162775694 +dew 1559902 93935940 +technologov 1154365 43136020 +grandphish2 988545 60725563 +tvijlbrief 795993 51894442 +TueRens 716909 45503672 +mibere 703840 46867607 +JojoM 675708 41046762 +okrout 648513 49953162 +linrock 563226 16184599 +pemo 520578 26816487 +gvreuls 501232 32662374 +cw 495103 33171295 +fastgm 476917 28660004 +crunchy 427035 27344275 +CSU_Dynasty 407300 27580858 +ctoks 386452 25757397 +oz 343309 25441096 +Fisherman 327231 21829379 +velislav 320318 20642978 +bcross 319459 22485737 +leszek 277442 17495865 +Dantist 229980 14568674 +mgrabiak 225684 14774260 +glinscott 217799 13780820 +nordlandia 211692 13484886 +robal 209847 13427680 +drabel 200340 13727458 +bking_US 198894 11876016 +Thanar 179852 12365359 +vdv 175274 9889046 +mhoram 166293 10796647 +spams 157128 10319326 +marrco 150300 9402229 +sqrt2 147963 9724586 +vdbergh 137186 8938965 +CoffeeOne 137100 5024116 +malala 136182 8002293 +xoto 133759 9159372 +davar 122092 7960001 +dsmith 122059 7570238 +amicic 119659 7937885 +Data 113305 8220352 +BrunoBanani 112960 7436849 +rpngn 109031 7392547 +CypressChess 108321 7759588 +MaZePallas 102823 6633619 +sterni1971 100532 5880772 +sunu 100167 7040199 +ElbertoOne 99028 7023771 +skiminki 98121 6478170 +brabos 92118 6186135 +psk 89957 5984901 +cuistot 88420 5225234 +DesolatedDodo 88356 5779482 +racerschmacer 85711 6119610 +Vizvezdenec 83761 5344740 +0x3C33 82614 5271253 +BRAVONE 81239 5054681 +nssy 76497 5259388 +teddybaer 75125 5407666 +Pking_cda 73776 5293873 +jromang 72192 5057715 +solarlight 70517 5028306 +dv8silencer 70287 3883992 +Bobo1239 68515 4652287 +manap 66273 4121774 +sschnee 64563 3633680 +tinker 64333 4268790 +zeryl 63290 4179159 +qurashee 61208 3429862 +yurikvelo 60387 4169900 +robnjr 57262 4053117 +Freja 56938 3733019 +ttruscott 56010 3680085 +rkl 55132 4164467 +renouve 53811 3501516 +finfish 51360 3370515 +eva42 51272 3599691 +Wolfgang 51248 3218932 +eastorwest 50311 3409935 +rap 49985 3219146 +pb00067 49727 3298270 +bigpen0r 47667 3336927 +ronaldjerum 47654 3240695 +MaxKlaxxMiner 47584 2972142 +biffhero 46564 3111352 +Spprtr 45877 2995437 +Fifis 45843 3088497 +VoyagerOne 45476 3452465 +speedycpu 43842 3003273 +jbwiebe 43305 2805433 +Antihistamine 41788 2761312 +mhunt 41735 2691355 +megaman7de 40060 2625050 +homyur 39893 2850481 +gri 39871 2515779 +oryx 38860 2976488 +SC 37299 2731694 +csnodgrass 36207 2688994 +jmdana 36157 2210661 +Garf 36113 2897580 +strelock 34716 2074055 +EthanOConnor 33370 2090311 +slakovv 32915 2021889 +manapbk 30987 1810399 +DMBK 30675 2383552 +Prcuvu 30377 2170122 +anst 30301 2190091 +jkiiski 30136 1904470 +hyperbolic.tom 29840 2017394 +chuckstablers 29659 2093438 +Pyafue 29650 1902349 +tolkki963 28171 1716386 +OuaisBla 27636 1578800 +armo9494 27224 2221042 +chriswk 26902 1868317 +achambord 26582 1767323 +gopeto 26355 1717722 +Patrick_G 26276 1801617 +yorkman 26193 1992080 +SFTUser 25182 1675689 +nabildanial 24942 1519409 +Sharaf_DG 24765 1786697 +ncfish1 24411 1520927 +rodneyc 24275 1410450 +agg177 23890 1395014 +JanErik 23408 1703875 +Isidor 23388 1680691 +Norabor 23339 1602636 +cisco2015 22897 1762669 +Zirie 22542 1472937 +Ente 22486 1606268 +team-oh 22272 1636708 +MazeOfGalious 21978 1629593 +sg4032 21947 1643265 +ianh2105 21725 1632562 +xor12 21628 1680365 +dex 21612 1467203 +nesoneg 21494 1463031 +sphinx 21211 1384728 +jjoshua2 21001 1423089 +horst.prack 20878 1465656 +0xB00B1ES 20590 1208666 +j3corre 20405 941444 +Adrian.Schmidt123 20316 1281436 +wei 19973 1745989 +rstoesser 19569 1293588 +eudhan 19274 1283717 +vulcan 18871 1729392 +user213718 18590 1271128 +jundery 18445 1115855 +iisiraider 18247 1101015 +ville 17883 1384026 +chris 17698 1487385 +purplefishies 17595 1092533 +dju 17353 978595 +DragonLord 17014 1162790 +IgorLeMasson 16064 1147232 +ako027ako 15671 1173203 +Nikolay.IT 15154 1068349 +Andrew Grant 15114 895539 +OssumOpossum 14857 1007129 +Karby 14808 867120 +enedene 14476 905279 +jsys14 14318 843704 +bpfliegel 14298 884523 +mpx86 14019 759568 +jpulman 13982 870599 +kdave 13933 1045550 +crocogoat 13803 1117422 +joster 13794 950160 +Nesa92 13786 1114691 +mbeier 13650 1044928 +AndreasKrug 13624 1090613 +Hjax 13535 915487 +Dark_wizzie 13422 1007152 +Ulysses 13392 1021264 +Calis007 13267 873236 +Rudolphous 13244 883140 +spcc 13085 917006 +Machariel 13010 863104 +mabichito 12903 749391 +thijsk 12886 722107 +AdrianSA 12860 804972 +Flopzee 12698 894821 +fatmurphy 12547 853210 +scuzzi 12511 845761 +SapphireBrand 12416 969604 +modolief 12386 896470 +fishtester 12320 873882 +Farseer 12249 694108 +pgontarz 12151 848794 +stocky 11954 699440 +mschmidt 11941 803401 +Maxim 11543 836024 +infinity 11470 727027 +aga 11409 695071 +torbjo 11395 729145 +pirt 11392 886291 +Thomas A. Anderson 11372 732094 +savage84 11358 670860 +FormazChar 11304 847663 +d64 11263 789184 +dbernier 11258 805102 +MooTheCow 11237 720174 +snicolet 11106 869170 +ali-al-zhrani 11098 768494 +basepi 10637 744851 +Cubox 10621 826448 +michaelrpg 10509 739239 +OIVAS7572 10420 995586 +dzjp 10343 732529 +infinigon 10319 776158 +Garruk 10314 702629 +ols 10259 570669 +lbraesch 10252 647825 From d579db34a3f7a26cd5502e79dafde2a80614d645 Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Fri, 10 Dec 2021 18:42:05 +0100 Subject: [PATCH 044/105] Simplify falling eval time factor. Remove the difference to previous best score in falling eval calculation. As compensation double the effect of the difference to previous best average score. STC: LLR: 2.95 (-2.94,2.94) <-2.25,0.25> Total: 86944 W: 22363 L: 22285 D: 42296 Ptnml(0-2): 273, 9227, 24396, 9301, 275 https://tests.stockfishchess.org/tests/view/61b111ce06b4c2dcb1b11546 LTC: LLR: 2.96 (-2.94,2.94) <-2.25,0.25> Total: 134944 W: 34606 L: 34596 D: 65742 Ptnml(0-2): 66, 12941, 41456, 12935, 74 https://tests.stockfishchess.org/tests/view/61b19ca206b4c2dcb1b13a8b closes https://github.com/official-stockfish/Stockfish/pull/3841 Bench: 4729473 --- src/search.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index cded8614..687bf0a9 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -490,9 +490,8 @@ void Thread::search() { && !Threads.stop && !mainThread->stopOnPonderhit) { - double fallingEval = (142 + 6 * (mainThread->bestPreviousScore - bestValue) - + 6 * (mainThread->bestPreviousAverageScore - bestValue) - + 6 * (mainThread->iterValue[iterIdx] - bestValue)) / 825.0; + double fallingEval = (142 + 12 * (mainThread->bestPreviousAverageScore - bestValue) + + 6 * (mainThread->iterValue[iterIdx] - bestValue)) / 825.0; fallingEval = std::clamp(fallingEval, 0.5, 1.5); // If the bestMove is stable over several iterations, reduce time accordingly From ea1ddb6aef8bb6ee3056988af7cfd32b2f52f960 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Sun, 12 Dec 2021 17:09:21 +0100 Subject: [PATCH 045/105] Update default net to nn-d93927199b3d.nnue Using the same dataset as before but slightly reduced initial LR as in https://github.com/vondele/nnue-pytorch/tree/tweakLR1 passed STC: LLR: 2.94 (-2.94,2.94) <0.00,2.50> Total: 51368 W: 13492 L: 13191 D: 24685 Ptnml(0-2): 168, 5767, 13526, 6042, 181 https://tests.stockfishchess.org/tests/view/61b61f43dffbe89a3580b529 passed LTC: LLR: 2.94 (-2.94,2.94) <0.50,3.00> Total: 45128 W: 11763 L: 11469 D: 21896 Ptnml(0-2): 24, 4583, 13063, 4863, 31 https://tests.stockfishchess.org/tests/view/61b6612edffbe89a3580c447 closes https://github.com/official-stockfish/Stockfish/pull/3848 Bench: 5121336 --- src/evaluate.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/evaluate.h b/src/evaluate.h index 87cb65f3..5a9260fb 100644 --- a/src/evaluate.h +++ b/src/evaluate.h @@ -39,7 +39,7 @@ namespace Eval { // The default net name MUST follow the format nn-[SHA256 first 12 digits].nnue // for the build process (profile-build and fishtest) to work. Do not change the // name of the macro, as it is used in the Makefile. - #define EvalFileDefaultName "nn-63376713ba63.nnue" + #define EvalFileDefaultName "nn-d93927199b3d.nnue" namespace NNUE { From c6edf33f539f160d4a7009f3aac25e7ec5668eda Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Tue, 7 Dec 2021 23:03:35 +0100 Subject: [PATCH 046/105] Remove NNUE scaling term remove pawns scaling, probably correlated with piece scaling, and might be less useful with the recent improved nets. Might allow for another tune of the scaling params. passed STC https://tests.stockfishchess.org/tests/view/61afdb2e56fcf33bce7df31a LLR: 2.95 (-2.94,2.94) <-2.25,0.25> Total: 280864 W: 72198 L: 72399 D: 136267 Ptnml(0-2): 854, 32356, 74346, 31889, 987 passed LTC https://tests.stockfishchess.org/tests/view/61b233a606b4c2dcb1b16140 LLR: 2.95 (-2.94,2.94) <-2.25,0.25> Total: 400136 W: 102669 L: 103012 D: 194455 Ptnml(0-2): 212, 42005, 116047, 41522, 282 closes https://github.com/official-stockfish/Stockfish/pull/3851 Bench: 4735679 --- src/evaluate.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 1dc701cf..24445f48 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -1091,8 +1091,7 @@ Value Eval::evaluate(const Position& pos) { v = Evaluation(pos).value(); // classical else { - int scale = 1049 - + 8 * pos.count() + int scale = 1136 + 20 * pos.non_pawn_material() / 1024; Value nnue = NNUE::evaluate(pos, true); // NNUE From 3bea736a2a63247d242316bd25d8901b1414d9c0 Mon Sep 17 00:00:00 2001 From: farseer Date: Wed, 15 Dec 2021 16:28:16 -0800 Subject: [PATCH 047/105] Update default net to nn-4401e826ebcc.nnue Using data T60 12/1/20 to 11/2/2021, T74 4/22/21 to 7/27/21, T75 6/3/21 to 10/16/21, T76 (half of the randomly interleaved dataset due to a mistake merging) 11/10/21 to 11/21/21, wrongIsRight_nodes5000pv2.binpack, and WrongIsRight-Reloaded.binpack combined and shuffled position by position. Trained with LR=4.375e-4 and WDL filtering enabled: python train.py --smart-fen-skipping --random-fen-skipping 0 --features=HalfKAv2_hm^ --lambda=1.0 --max_epochs=800 --seed 910688689 --batch-size 16384 --progress_bar_refresh_rate 30 --threads 4 --num-workers 4 --gpus 1 --resume-from-model C:\msys64\home\Mike\nnue-pytorch\9b3d.pt E:\trainingdata\T60-T74-T75-T76-WiR-WiRR-PbyP.binpack E:\trainingdata\T60-T74-T75-T76-WiR-WiRR-PbyP.binpack Passed STC LLR: 2.94 (-2.94,2.94) <0.00,2.50> Total: 41848 W: 10962 L: 10676 D: 20210 Elo +2.16 Ptnml(0-2): 142, 4699, 11016, 4865, 202 https://tests.stockfishchess.org/tests/view/61ba886857a0d0f327c2cfd6 Passed LTC LLR: 2.94 (-2.94,2.94) <0.50,3.00> Total: 27776 W: 7208 L: 6953 D: 13615 Elo + 3.00 Ptnml(0-2): 14, 2808, 8007, 3027, 32 https://tests.stockfishchess.org/tests/view/61baae4d57a0d0f327c2d96f closes https://github.com/official-stockfish/Stockfish/pull/3856 Bench: 4667591 --- src/evaluate.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/evaluate.h b/src/evaluate.h index 5a9260fb..e258fdb6 100644 --- a/src/evaluate.h +++ b/src/evaluate.h @@ -39,7 +39,7 @@ namespace Eval { // The default net name MUST follow the format nn-[SHA256 first 12 digits].nnue // for the build process (profile-build and fishtest) to work. Do not change the // name of the macro, as it is used in the Makefile. - #define EvalFileDefaultName "nn-d93927199b3d.nnue" + #define EvalFileDefaultName "nn-4401e826ebcc.nnue" namespace NNUE { From 0889210262ab5a14bc6fcd261125b919120637a0 Mon Sep 17 00:00:00 2001 From: bmc4 Date: Tue, 14 Dec 2021 12:00:45 -0300 Subject: [PATCH 048/105] Simplify away singularQuietLMR While at it, we also update the Elo estimate of reduction at non-PV nodes (source: https://tests.stockfishchess.org/tests/view/61acf97156fcf33bce7d6303 ) STC: LLR: 2.94 (-2.94,2.94) <-2.25,0.25> Total: 243632 W: 62874 L: 63022 D: 117736 Ptnml(0-2): 810, 28024, 64249, 27970, 763 https://tests.stockfishchess.org/tests/view/61b8b1b7dffbe89a35814c0d LTC: LLR: 2.93 (-2.94,2.94) <-2.25,0.25> Total: 91392 W: 23520 L: 23453 D: 44419 Ptnml(0-2): 51, 9568, 26387, 9643, 47 https://tests.stockfishchess.org/tests/view/61b97316dffbe89a35817da7 closes https://github.com/official-stockfish/Stockfish/pull/3854 bench: 4217785 --- src/search.cpp | 12 +++--------- 1 file changed, 3 insertions(+), 9 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 687bf0a9..01d97646 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -590,8 +590,7 @@ namespace { Depth extension, newDepth; Value bestValue, value, ttValue, eval, maxValue, probCutBeta; bool givesCheck, improving, didLMR, priorCapture; - bool captureOrPromotion, doFullDepthSearch, moveCountPruning, - ttCapture, singularQuietLMR; + bool captureOrPromotion, doFullDepthSearch, moveCountPruning, ttCapture; Piece movedPiece; int moveCount, captureCount, quietCount, bestMoveCount, improvement; @@ -982,7 +981,7 @@ moves_loop: // When in check, search starts here ss->ply); value = bestValue; - singularQuietLMR = moveCountPruning = false; + moveCountPruning = false; // Indicate PvNodes that will probably fail low if the node was searched // at a depth equal or greater than the current depth, and the result of this search was a fail low. @@ -1106,7 +1105,6 @@ moves_loop: // When in check, search starts here if (value < singularBeta) { extension = 1; - singularQuietLMR = !ttCapture; // Avoid search explosion by limiting the number of double extensions if ( !PvNode @@ -1190,7 +1188,7 @@ moves_loop: // When in check, search starts here && !likelyFailLow) r -= 2; - // Increase reduction at non-PV nodes + // Increase reduction at non-PV nodes (~3 Elo) if (!PvNode) r++; @@ -1198,10 +1196,6 @@ moves_loop: // When in check, search starts here if ((ss-1)->moveCount > 13) r--; - // Decrease reduction if ttMove has been singularly extended (~1 Elo) - if (singularQuietLMR) - r--; - // Increase reduction for cut nodes (~3 Elo) if (cutNode && move != ss->killers[0]) r += 2; From dc5d9bdfee70f4267d9a49ad71e5ee478dd50ca5 Mon Sep 17 00:00:00 2001 From: pb00067 Date: Wed, 15 Dec 2021 08:49:44 +0100 Subject: [PATCH 049/105] Remove lowPly history Seems that after pull request #3731 (Capping stat bonus at 2000) this heuristic is no longer useful. STC: https://tests.stockfishchess.org/tests/view/61b8d0e2dffbe89a35815444 LLR: 2.94 (-2.94,2.94) <-2.25,0.25> Total: 30672 W: 7974 L: 7812 D: 14886 Ptnml(0-2): 106, 3436, 8072, 3634, 88 LTC: https://tests.stockfishchess.org/tests/view/61b8e90cdffbe89a35815a67 LLR: 2.94 (-2.94,2.94) <-2.25,0.25> Total: 42448 W: 10884 L: 10751 D: 20813 Ptnml(0-2): 23, 4394, 12267, 4507, 33 closes https://github.com/official-stockfish/Stockfish/pull/3853 bench: 4474950 --- src/movepick.cpp | 28 ++++++++++++++++------------ src/movepick.h | 22 ++++++---------------- src/search.cpp | 27 +++++---------------------- src/thread.cpp | 1 - src/thread.h | 1 - 5 files changed, 27 insertions(+), 52 deletions(-) diff --git a/src/movepick.cpp b/src/movepick.cpp index 20640fe2..6aa1954b 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -56,11 +56,14 @@ namespace { /// ordering is at the current node. /// MovePicker constructor for the main search -MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, const LowPlyHistory* lp, - const CapturePieceToHistory* cph, const PieceToHistory** ch, Move cm, const Move* killers, int pl) - : pos(p), mainHistory(mh), lowPlyHistory(lp), captureHistory(cph), continuationHistory(ch), - ttMove(ttm), refutations{{killers[0], 0}, {killers[1], 0}, {cm, 0}}, depth(d), ply(pl) { - +MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, + const CapturePieceToHistory* cph, + const PieceToHistory** ch, + Move cm, + const Move* killers) + : pos(p), mainHistory(mh), captureHistory(cph), continuationHistory(ch), + ttMove(ttm), refutations{{killers[0], 0}, {killers[1], 0}, {cm, 0}}, depth(d) +{ assert(d > 0); stage = (pos.checkers() ? EVASION_TT : MAIN_TT) + @@ -69,9 +72,11 @@ MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHist /// MovePicker constructor for quiescence search MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHistory* mh, - const CapturePieceToHistory* cph, const PieceToHistory** ch, Square rs) - : pos(p), mainHistory(mh), captureHistory(cph), continuationHistory(ch), ttMove(ttm), recaptureSquare(rs), depth(d) { - + const CapturePieceToHistory* cph, + const PieceToHistory** ch, + Square rs) + : pos(p), mainHistory(mh), captureHistory(cph), continuationHistory(ch), ttMove(ttm), recaptureSquare(rs), depth(d) +{ assert(d <= 0); stage = (pos.checkers() ? EVASION_TT : QSEARCH_TT) + @@ -83,8 +88,8 @@ MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHist /// MovePicker constructor for ProbCut: we generate captures with SEE greater /// than or equal to the given threshold. MovePicker::MovePicker(const Position& p, Move ttm, Value th, const CapturePieceToHistory* cph) - : pos(p), captureHistory(cph), ttMove(ttm), threshold(th) { - + : pos(p), captureHistory(cph), ttMove(ttm), threshold(th) +{ assert(!pos.checkers()); stage = PROBCUT_TT + !(ttm && pos.capture(ttm) @@ -110,8 +115,7 @@ void MovePicker::score() { + 2 * (*continuationHistory[0])[pos.moved_piece(m)][to_sq(m)] + (*continuationHistory[1])[pos.moved_piece(m)][to_sq(m)] + (*continuationHistory[3])[pos.moved_piece(m)][to_sq(m)] - + (*continuationHistory[5])[pos.moved_piece(m)][to_sq(m)] - + (ply < MAX_LPH ? 6 * (*lowPlyHistory)[ply][from_to(m)] : 0); + + (*continuationHistory[5])[pos.moved_piece(m)][to_sq(m)]; else // Type == EVASIONS { diff --git a/src/movepick.h b/src/movepick.h index 7d78886f..426bac89 100644 --- a/src/movepick.h +++ b/src/movepick.h @@ -88,12 +88,6 @@ enum StatsType { NoCaptures, Captures }; /// the move's from and to squares, see www.chessprogramming.org/Butterfly_Boards typedef Stats ButterflyHistory; -/// At higher depths LowPlyHistory records successful quiet moves near the root -/// and quiet moves which are/were in the PV (ttPv). LowPlyHistory is populated during -/// iterative deepening and at each new search the data is shifted down by 2 plies -constexpr int MAX_LPH = 4; -typedef Stats LowPlyHistory; - /// CounterMoveHistory stores counter moves indexed by [piece][to] of the previous /// move, see www.chessprogramming.org/Countermove_Heuristic typedef Stats CounterMoveHistory; @@ -123,18 +117,16 @@ class MovePicker { public: MovePicker(const MovePicker&) = delete; MovePicker& operator=(const MovePicker&) = delete; - MovePicker(const Position&, Move, Value, const CapturePieceToHistory*); + MovePicker(const Position&, Move, Depth, const ButterflyHistory*, + const CapturePieceToHistory*, + const PieceToHistory**, + Move, + const Move*); MovePicker(const Position&, Move, Depth, const ButterflyHistory*, const CapturePieceToHistory*, const PieceToHistory**, Square); - MovePicker(const Position&, Move, Depth, const ButterflyHistory*, - const LowPlyHistory*, - const CapturePieceToHistory*, - const PieceToHistory**, - Move, - const Move*, - int); + MovePicker(const Position&, Move, Value, const CapturePieceToHistory*); Move next_move(bool skipQuiets = false); private: @@ -145,7 +137,6 @@ private: const Position& pos; const ButterflyHistory* mainHistory; - const LowPlyHistory* lowPlyHistory; const CapturePieceToHistory* captureHistory; const PieceToHistory** continuationHistory; Move ttMove; @@ -154,7 +145,6 @@ private: Square recaptureSquare; Value threshold; Depth depth; - int ply; ExtMove moves[MAX_MOVES]; }; diff --git a/src/search.cpp b/src/search.cpp index 01d97646..2abfbaf2 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -141,7 +141,7 @@ namespace { Value value_from_tt(Value v, int ply, int r50c); void update_pv(Move* pv, Move move, Move* childPv); void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus); - void update_quiet_stats(const Position& pos, Stack* ss, Move move, int bonus, int depth); + void update_quiet_stats(const Position& pos, Stack* ss, Move move, int bonus); void update_all_stats(const Position& pos, Stack* ss, Move bestMove, Value bestValue, Value beta, Square prevSq, Move* quietsSearched, int quietCount, Move* capturesSearched, int captureCount, Depth depth); @@ -317,9 +317,6 @@ void Thread::search() { mainThread->iterValue[i] = mainThread->bestPreviousScore; } - std::copy(&lowPlyHistory[2][0], &lowPlyHistory.back().back() + 1, &lowPlyHistory[0][0]); - std::fill(&lowPlyHistory[MAX_LPH - 2][0], &lowPlyHistory.back().back() + 1, 0); - size_t multiPV = size_t(Options["MultiPV"]); Skill skill(Options["Skill Level"], Options["UCI_LimitStrength"] ? int(Options["UCI_Elo"]) : 0); @@ -666,14 +663,6 @@ namespace { if (!excludedMove) ss->ttPv = PvNode || (ss->ttHit && tte->is_pv()); - // Update low ply history for previous move if we are near root and position is or has been in PV - if ( ss->ttPv - && depth > 12 - && ss->ply - 1 < MAX_LPH - && !priorCapture - && is_ok((ss-1)->currentMove)) - thisThread->lowPlyHistory[ss->ply - 1][from_to((ss-1)->currentMove)] << stat_bonus(depth - 5); - // At non-PV nodes we check for an early TT cutoff if ( !PvNode && ss->ttHit @@ -689,7 +678,7 @@ namespace { { // Bonus for a quiet ttMove that fails high if (!ttCapture) - update_quiet_stats(pos, ss, ttMove, stat_bonus(depth), depth); + update_quiet_stats(pos, ss, ttMove, stat_bonus(depth)); // Extra penalty for early quiet moves of the previous ply if ((ss-1)->moveCount <= 2 && !priorCapture) @@ -973,12 +962,10 @@ moves_loop: // When in check, search starts here Move countermove = thisThread->counterMoves[pos.piece_on(prevSq)][prevSq]; MovePicker mp(pos, ttMove, depth, &thisThread->mainHistory, - &thisThread->lowPlyHistory, &captureHistory, contHist, countermove, - ss->killers, - ss->ply); + ss->killers); value = bestValue; moveCountPruning = false; @@ -1708,7 +1695,7 @@ moves_loop: // When in check, search starts here if (!pos.capture_or_promotion(bestMove)) { // Increase stats for the best move in case it was a quiet move - update_quiet_stats(pos, ss, bestMove, bonus2, depth); + update_quiet_stats(pos, ss, bestMove, bonus2); // Decrease stats for all non-best quiet moves for (int i = 0; i < quietCount; ++i) @@ -1755,7 +1742,7 @@ moves_loop: // When in check, search starts here // update_quiet_stats() updates move sorting heuristics - void update_quiet_stats(const Position& pos, Stack* ss, Move move, int bonus, int depth) { + void update_quiet_stats(const Position& pos, Stack* ss, Move move, int bonus) { // Update killers if (ss->killers[0] != move) @@ -1775,10 +1762,6 @@ moves_loop: // When in check, search starts here Square prevSq = to_sq((ss-1)->currentMove); thisThread->counterMoves[pos.piece_on(prevSq)][prevSq] = move; } - - // Update low ply history - if (depth > 11 && ss->ply < MAX_LPH) - thisThread->lowPlyHistory[ss->ply][from_to(move)] << stat_bonus(depth - 7); } // When playing with strength handicap, choose best move among a set of RootMoves diff --git a/src/thread.cpp b/src/thread.cpp index ed3accc5..099efbad 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -59,7 +59,6 @@ void Thread::clear() { counterMoves.fill(MOVE_NONE); mainHistory.fill(0); - lowPlyHistory.fill(0); captureHistory.fill(0); for (bool inCheck : { false, true }) diff --git a/src/thread.h b/src/thread.h index 37c6452b..6bc1be65 100644 --- a/src/thread.h +++ b/src/thread.h @@ -77,7 +77,6 @@ public: Value rootDelta; CounterMoveHistory counterMoves; ButterflyHistory mainHistory; - LowPlyHistory lowPlyHistory; CapturePieceToHistory captureHistory; ContinuationHistory continuationHistory[2][2]; Score trend; From 939b694bfda27017c34a8cdccc81f2bb2ef44079 Mon Sep 17 00:00:00 2001 From: George Sobala Date: Mon, 13 Dec 2021 15:29:31 +0000 Subject: [PATCH 050/105] Fix for profile-build failure using gcc on MacOS Fixes https://github.com/official-stockfish/Stockfish/issues/3846 , where the profiling SF binary generated by GCC on MacOS would launch but failed to quit. Tested with gcc-8, gcc9, gcc10, gcc-11. The problem can be fixed by adding -fvisibility=hidden to the compiler flags, see for example the following piece of Apple documentation: https://developer.apple.com/library/archive/documentation/DeveloperTools/Conceptual/CppRuntimeEnv/Articles/SymbolVisibility.html For instance this now works: make -j8 profile-build ARCH=x86-64-avx2 COMP=gcc COMPCXX=g++-11 No functional change --- src/Makefile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/Makefile b/src/Makefile index 3cf97873..5e263772 100644 --- a/src/Makefile +++ b/src/Makefile @@ -459,6 +459,9 @@ else ifeq ($(comp),clang) else profile_make = gcc-profile-make profile_use = gcc-profile-use + ifeq ($(KERNEL),Darwin) + EXTRAPROFILEFLAGS = -fvisibility=hidden + endif endif ### Travis CI script uses COMPILER to overwrite CXX @@ -920,12 +923,14 @@ gcc-profile-make: @mkdir -p profdir $(MAKE) ARCH=$(ARCH) COMP=$(COMP) \ EXTRACXXFLAGS='-fprofile-generate=profdir' \ + EXTRACXXFLAGS+=$(EXTRAPROFILEFLAGS) \ EXTRALDFLAGS='-lgcov' \ all gcc-profile-use: $(MAKE) ARCH=$(ARCH) COMP=$(COMP) \ EXTRACXXFLAGS='-fprofile-use=profdir -fno-peel-loops -fno-tracer' \ + EXTRACXXFLAGS+=$(EXTRAPROFILEFLAGS) \ EXTRALDFLAGS='-lgcov' \ all From 0a318cdddf8b6bdd05c2e0ee9b3b61a031d398ed Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Sat, 18 Dec 2021 11:51:19 +0300 Subject: [PATCH 051/105] Adjust reductions based on current node delta and root delta This patch is a follow up of previous 2 patches that introduced more reductions for PV nodes with low delta and more pruning for nodes with low delta. Instead of writing separate heuristics now it adjust reductions based on delta / rootDelta - it allows to remove 3 separate adjustements of pruning/LMR in different places and also makes reduction dependence on delta and rootDelta smoother. Also now it works for all pruning heuristics and not just 2. Passed STC https://tests.stockfishchess.org/tests/view/61ba9b6c57a0d0f327c2d48b LLR: 2.94 (-2.94,2.94) <0.00,2.50> Total: 79192 W: 20513 L: 20163 D: 38516 Ptnml(0-2): 238, 8900, 21024, 9142, 292 passed LTC https://tests.stockfishchess.org/tests/view/61baf77557a0d0f327c2eb8e LLR: 2.96 (-2.94,2.94) <0.50,3.00> Total: 158400 W: 41134 L: 40572 D: 76694 Ptnml(0-2): 101, 16372, 45745, 16828, 154 closes https://github.com/official-stockfish/Stockfish/pull/3862 bench 4651538 --- src/search.cpp | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 2abfbaf2..8a4db351 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -69,9 +69,9 @@ namespace { // Reductions lookup table, initialized at startup int Reductions[MAX_MOVES]; // [depth or moveNumber] - Depth reduction(bool i, Depth d, int mn, bool rangeReduction) { + Depth reduction(bool i, Depth d, int mn, bool rangeReduction, Value delta, Value rootDelta) { int r = Reductions[d] * Reductions[mn]; - return (r + 534) / 1024 + (!i && r > 904) + rangeReduction; + return (r + 1358 - int(delta) * 1024 / int(rootDelta)) / 1024 + (!i && r > 904) + rangeReduction; } constexpr int futility_move_count(bool improving, Depth depth) { @@ -1015,6 +1015,8 @@ moves_loop: // When in check, search starts here // Calculate new depth for this move newDepth = depth - 1; + Value delta = beta - alpha; + // Step 13. Pruning at shallow depth (~200 Elo). Depth conditions are important for mate finding. if ( !rootNode && pos.non_pawn_material(us) @@ -1024,7 +1026,7 @@ moves_loop: // When in check, search starts here moveCountPruning = moveCount >= futility_move_count(improving, depth); // Reduced depth of the next LMR search - int lmrDepth = std::max(newDepth - reduction(improving, depth, moveCount, rangeReduction > 2), 0); + int lmrDepth = std::max(newDepth - reduction(improving, depth, moveCount, rangeReduction > 2, delta, thisThread->rootDelta), 0); if ( captureOrPromotion || givesCheck) @@ -1052,8 +1054,6 @@ moves_loop: // When in check, search starts here history += thisThread->mainHistory[us][from_to(move)]; - lmrDepth = std::max(0, lmrDepth - (beta - alpha < thisThread->rootDelta / 4)); - // Futility pruning: parent node (~5 Elo) if ( !ss->inCheck && lmrDepth < 8 @@ -1161,12 +1161,11 @@ moves_loop: // When in check, search starts here || !captureOrPromotion || (cutNode && (ss-1)->moveCount > 1))) { - Depth r = reduction(improving, depth, moveCount, rangeReduction > 2); + Depth r = reduction(improving, depth, moveCount, rangeReduction > 2, delta, thisThread->rootDelta); // Decrease reduction at some PvNodes (~2 Elo) if ( PvNode - && bestMoveCount <= 3 - && beta - alpha >= thisThread->rootDelta / 4) + && bestMoveCount <= 3) r--; // Decrease reduction if position is or has been on the PV @@ -1175,10 +1174,6 @@ moves_loop: // When in check, search starts here && !likelyFailLow) r -= 2; - // Increase reduction at non-PV nodes (~3 Elo) - if (!PvNode) - r++; - // Decrease reduction if opponent's move count is high (~1 Elo) if ((ss-1)->moveCount > 13) r--; From fb7d3ab32ebd7a6514bded459b4aa442276f6cda Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Sun, 19 Dec 2021 02:30:45 +0300 Subject: [PATCH 052/105] Reintroduce futility pruning for captures This is a reintroduction of an idea that was simplified away approximately 1 year ago. There are some tweaks to it : a) exclude promotions; b) exclude Pv Nodes from it - Pv Nodes logic for captures is really different from non Pv nodes so it makes a lot of sense; c) use a big grain of capture history - idea is taken from my recent patches in futility pruning. passed STC https://tests.stockfishchess.org/tests/view/61bd90f857a0d0f327c373b7 LLR: 2.96 (-2.94,2.94) <0.00,2.50> Total: 86640 W: 22474 L: 22110 D: 42056 Ptnml(0-2): 268, 9732, 22963, 10082, 275 passed LTC https://tests.stockfishchess.org/tests/view/61be094457a0d0f327c38aa3 LLR: 2.95 (-2.94,2.94) <0.50,3.00> Total: 23240 W: 6079 L: 5838 D: 11323 Ptnml(0-2): 14, 2261, 6824, 2512, 9 https://github.com/official-stockfish/Stockfish/pull/3864 bench 4493723 --- src/search.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/search.cpp b/src/search.cpp index 8a4db351..d2ceee9f 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1037,6 +1037,16 @@ moves_loop: // When in check, search starts here && captureHistory[movedPiece][to_sq(move)][type_of(pos.piece_on(to_sq(move)))] < 0) continue; + // Futility pruning for captures + if ( !pos.empty(to_sq(move)) + && !givesCheck + && !PvNode + && lmrDepth < 6 + && !ss->inCheck + && ss->staticEval + 342 + 238 * lmrDepth + PieceValue[EG][pos.piece_on(to_sq(move))] + + captureHistory[movedPiece][to_sq(move)][type_of(pos.piece_on(to_sq(move)))] / 8 < alpha) + continue; + // SEE based pruning if (!pos.see_ge(move, Value(-218) * depth)) // (~25 Elo) continue; From ca51b456493a4663b2d0f82273f67a3e499244a1 Mon Sep 17 00:00:00 2001 From: George Sobala Date: Mon, 13 Dec 2021 16:05:35 +0000 Subject: [PATCH 053/105] Fixes build failure on Apple M1 Silicon This pull request selectively avoids `-mdynamic-no-pic` for gcc on Apple Silicon (there was no problem with the default clang compiler). fixes https://github.com/official-stockfish/Stockfish/issues/3847 closes https://github.com/official-stockfish/Stockfish/pull/3850 No functional change --- src/Makefile | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/Makefile b/src/Makefile index 5e263772..f00df79f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -522,11 +522,17 @@ ifeq ($(optimize),yes) endif endif - ifeq ($(comp),$(filter $(comp),gcc clang icc)) - ifeq ($(KERNEL),Darwin) - CXXFLAGS += -mdynamic-no-pic - endif - endif + ifeq ($(KERNEL),Darwin) + ifeq ($(comp),$(filter $(comp),clang icc)) + CXXFLAGS += -mdynamic-no-pic + endif + + ifeq ($(comp),gcc) + ifneq ($(arch),arm64) + CXXFLAGS += -mdynamic-no-pic + endif + endif + endif ifeq ($(comp),clang) CXXFLAGS += -fexperimental-new-pass-manager From 74776dbcd57a1bdf2d5328e5750cc1d00244e17d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolet?= Date: Sun, 19 Dec 2021 15:15:30 +0100 Subject: [PATCH 054/105] Simplification in evaluate_nnue.cpp Removes the test on non-pawn-material before applying the positional/materialistic bonus. Passed STC: LLR: 2.94 (-2.94,2.94) <-2.25,0.25> Total: 46904 W: 12197 L: 12059 D: 22648 Ptnml(0-2): 170, 5243, 12479, 5399, 161 https://tests.stockfishchess.org/tests/view/61be57cf57a0d0f327c3999d Passed LTC: LLR: 2.95 (-2.94,2.94) <-2.25,0.25> Total: 18760 W: 4958 L: 4790 D: 9012 Ptnml(0-2): 14, 1942, 5301, 2108, 15 https://tests.stockfishchess.org/tests/view/61bed1fb57a0d0f327c3afa9 closes https://github.com/official-stockfish/Stockfish/pull/3866 Bench: 4826206 --- src/nnue/evaluate_nnue.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/nnue/evaluate_nnue.cpp b/src/nnue/evaluate_nnue.cpp index bd473294..a534753a 100644 --- a/src/nnue/evaluate_nnue.cpp +++ b/src/nnue/evaluate_nnue.cpp @@ -165,12 +165,11 @@ namespace Stockfish::Eval::NNUE { const auto psqt = featureTransformer->transform(pos, transformedFeatures, bucket); const auto positional = network[bucket]->propagate(transformedFeatures, buffer)[0]; - // Give more value to positional evaluation when material is balanced - if ( adjusted - && abs(pos.non_pawn_material(WHITE) - pos.non_pawn_material(BLACK)) <= RookValueMg - BishopValueMg) - return static_cast(((128 - delta) * psqt + (128 + delta) * positional) / 128 / OutputScale); + // Give more value to positional evaluation when adjusted flag is set + if (adjusted) + return static_cast(((128 - delta) * psqt + (128 + delta) * positional) / 128 / OutputScale); else - return static_cast((psqt + positional) / OutputScale); + return static_cast((psqt + positional) / OutputScale); } struct NnueEvalTrace { From 2c30956a13986454dcc5dd8c7daa1b27d5a77a1b Mon Sep 17 00:00:00 2001 From: bmc4 Date: Fri, 17 Dec 2021 21:14:34 -0300 Subject: [PATCH 055/105] Remove Capture Extension This revert the patch #3692, probably can be simplified after the introduction of #3838. Fixed-game test: ELO: -1.41 +-1.8 (95%) LOS: 5.9% Total: 20000 W: 1552 L: 1633 D: 16815 Ptnml(0-2): 38, 1242, 7517, 1169, 34 https://tests.stockfishchess.org/tests/view/61bc1a2057a0d0f327c32a3c STC: LLR: 2.94 (-2.94,2.94) <-2.25,0.25> Total: 44528 W: 11619 L: 11478 D: 21431 Ptnml(0-2): 146, 5020, 11771, 5201, 126 https://tests.stockfishchess.org/tests/view/61bc638c57a0d0f327c338fe LTC: LLR: 2.94 (-2.94,2.94) <-2.25,0.25> Total: 34136 W: 8847 L: 8704 D: 16585 Ptnml(0-2): 23, 3475, 9925, 3626, 19 https://tests.stockfishchess.org/tests/view/61bcb24257a0d0f327c34813 closes https://github.com/official-stockfish/Stockfish/pull/3863 Bench: 4054695 --- src/search.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index d2ceee9f..eb0ac5bb 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1123,12 +1123,6 @@ moves_loop: // When in check, search starts here extension = -2; } - // Capture extensions for PvNodes and cutNodes - else if ( (PvNode || cutNode) - && captureOrPromotion - && moveCount != 1) - extension = 1; - // Check extensions else if ( givesCheck && depth > 6 From 22e92d23d24ade1053cf543624d0efd01387e886 Mon Sep 17 00:00:00 2001 From: bmc4 Date: Mon, 20 Dec 2021 08:08:09 -0300 Subject: [PATCH 056/105] Remove Capture history pruning Fixed number of games. (book: 8moves_v3.png): ELO: -0.69 +-1.8 (95%) LOS: 22.1% Total: 20000 W: 1592 L: 1632 D: 16776 Ptnml(0-2): 44, 1194, 7566, 1150, 46 https://tests.stockfishchess.org/tests/view/61bb8eb657a0d0f327c30ce8 STC: LLR: 2.94 (-2.94,2.94) <-2.25,0.25> Total: 139976 W: 36039 L: 36036 D: 67901 Ptnml(0-2): 435, 16138, 36885, 16049, 481 https://tests.stockfishchess.org/tests/view/61be731857a0d0f327c39ea2 LTC: LLR: 2.95 (-2.94,2.94) <-2.25,0.25> Total: 70656 W: 18284 L: 18189 D: 34183 Ptnml(0-2): 34, 7317, 20529, 7416, 32 https://tests.stockfishchess.org/tests/view/61bf39b657a0d0f327c3c37b closes https://github.com/official-stockfish/Stockfish/pull/3867 bench: 4281737 --- src/search.cpp | 6 ------ 1 file changed, 6 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index eb0ac5bb..988166df 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1031,12 +1031,6 @@ moves_loop: // When in check, search starts here if ( captureOrPromotion || givesCheck) { - // Capture history based pruning when the move doesn't give check - if ( !givesCheck - && lmrDepth < 1 - && captureHistory[movedPiece][to_sq(move)][type_of(pos.piece_on(to_sq(move)))] < 0) - continue; - // Futility pruning for captures if ( !pos.empty(to_sq(move)) && !givesCheck From 88f17a814d80cdb32ccf9efb7b56bb36d7bf052b Mon Sep 17 00:00:00 2001 From: bmc4 Date: Mon, 20 Dec 2021 16:20:08 -0300 Subject: [PATCH 057/105] Update Elo estimates for terms in search This updates estimates from 2yr ago #2401, and adds missing terms. All tests run at 10+0.1 (STC), 20000 games, error bars +- 1.8 Elo, book 8moves_v3.png. A table of Elo values with the links to the corresponding tests can be found at the PR closes https://github.com/official-stockfish/Stockfish/pull/3868 Non-functional Change --- src/evaluate.cpp | 2 +- src/search.cpp | 56 ++++++++++++++++++++++++------------------------ 2 files changed, 29 insertions(+), 29 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 24445f48..28689f1d 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -1083,7 +1083,7 @@ Value Eval::evaluate(const Position& pos) { Value v; - // Deciding between classical and NNUE eval: for high PSQ imbalance we use classical, + // Deciding between classical and NNUE eval (~10 Elo): for high PSQ imbalance we use classical, // but we switch to NNUE during long shuffling or with high material on the board. if ( !useNNUE diff --git a/src/search.cpp b/src/search.cpp index 988166df..f5e9779c 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -671,20 +671,20 @@ namespace { && (ttValue >= beta ? (tte->bound() & BOUND_LOWER) : (tte->bound() & BOUND_UPPER))) { - // If ttMove is quiet, update move sorting heuristics on TT hit + // If ttMove is quiet, update move sorting heuristics on TT hit (~1 Elo) if (ttMove) { if (ttValue >= beta) { - // Bonus for a quiet ttMove that fails high + // Bonus for a quiet ttMove that fails high (~3 Elo) if (!ttCapture) update_quiet_stats(pos, ss, ttMove, stat_bonus(depth)); - // Extra penalty for early quiet moves of the previous ply + // Extra penalty for early quiet moves of the previous ply (~0 Elo) if ((ss-1)->moveCount <= 2 && !priorCapture) update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, -stat_bonus(depth + 1)); } - // Penalty for a quiet ttMove that fails low + // Penalty for a quiet ttMove that fails low (~1 Elo) else if (!ttCapture) { int penalty = -stat_bonus(depth); @@ -773,7 +773,7 @@ namespace { if (eval == VALUE_DRAW) eval = value_draw(thisThread); - // Can ttValue be used as a better position evaluation? + // ttValue can be used as a better position evaluation (~4 Elo) if ( ttValue != VALUE_NONE && (tte->bound() & (ttValue > eval ? BOUND_LOWER : BOUND_UPPER))) eval = ttValue; @@ -787,7 +787,7 @@ namespace { tte->save(posKey, VALUE_NONE, ss->ttPv, BOUND_NONE, DEPTH_NONE, MOVE_NONE, eval); } - // Use static evaluation difference to improve quiet move ordering + // Use static evaluation difference to improve quiet move ordering (~3 Elo) if (is_ok((ss-1)->currentMove) && !(ss-1)->inCheck && !priorCapture) { int bonus = std::clamp(-16 * int((ss-1)->staticEval + ss->staticEval), -2000, 2000); @@ -804,7 +804,7 @@ namespace { improving = improvement > 0; - // Step 7. Futility pruning: child node (~50 Elo). + // Step 7. Futility pruning: child node (~25 Elo). // The depth condition is important for mate finding. if ( !ss->ttPv && depth < 9 @@ -812,7 +812,7 @@ namespace { && eval < 15000) // 50% larger than VALUE_KNOWN_WIN, but smaller than TB wins. return eval; - // Step 8. Null move search with verification search (~40 Elo) + // Step 8. Null move search with verification search (~22 Elo) if ( !PvNode && (ss-1)->currentMove != MOVE_NULL && (ss-1)->statScore < 23767 @@ -925,7 +925,7 @@ namespace { ss->ttPv = ttPv; } - // Step 10. If the position is not in TT, decrease depth by 2 or 1 depending on node type + // Step 10. If the position is not in TT, decrease depth by 2 or 1 depending on node type (~3 Elo) if ( PvNode && depth >= 6 && !ttMove) @@ -940,7 +940,7 @@ moves_loop: // When in check, search starts here int rangeReduction = 0; - // Step 11. A small Probcut idea, when we are in check + // Step 11. A small Probcut idea, when we are in check (~0 Elo) probCutBeta = beta + 409; if ( ss->inCheck && !PvNode @@ -1017,12 +1017,12 @@ moves_loop: // When in check, search starts here Value delta = beta - alpha; - // Step 13. Pruning at shallow depth (~200 Elo). Depth conditions are important for mate finding. + // Step 13. Pruning at shallow depth (~98 Elo). Depth conditions are important for mate finding. if ( !rootNode && pos.non_pawn_material(us) && bestValue > VALUE_TB_LOSS_IN_MAX_PLY) { - // Skip quiet moves if movecount exceeds our FutilityMoveCount threshold + // Skip quiet moves if movecount exceeds our FutilityMoveCount threshold (~7 Elo) moveCountPruning = moveCount >= futility_move_count(improving, depth); // Reduced depth of the next LMR search @@ -1031,18 +1031,18 @@ moves_loop: // When in check, search starts here if ( captureOrPromotion || givesCheck) { - // Futility pruning for captures + // Futility pruning for captures (~0 Elo) if ( !pos.empty(to_sq(move)) && !givesCheck && !PvNode && lmrDepth < 6 && !ss->inCheck - && ss->staticEval + 342 + 238 * lmrDepth + PieceValue[EG][pos.piece_on(to_sq(move))] + && ss->staticEval + 342 + 238 * lmrDepth + PieceValue[EG][pos.piece_on(to_sq(move))] + captureHistory[movedPiece][to_sq(move)][type_of(pos.piece_on(to_sq(move)))] / 8 < alpha) continue; - // SEE based pruning - if (!pos.see_ge(move, Value(-218) * depth)) // (~25 Elo) + // SEE based pruning (~9 Elo) + if (!pos.see_ge(move, Value(-218) * depth)) continue; } else @@ -1051,28 +1051,28 @@ moves_loop: // When in check, search starts here + (*contHist[1])[movedPiece][to_sq(move)] + (*contHist[3])[movedPiece][to_sq(move)]; - // Continuation history based pruning (~20 Elo) + // Continuation history based pruning (~2 Elo) if ( lmrDepth < 5 && history < -3000 * depth + 3000) continue; history += thisThread->mainHistory[us][from_to(move)]; - // Futility pruning: parent node (~5 Elo) + // Futility pruning: parent node (~9 Elo) if ( !ss->inCheck && lmrDepth < 8 && ss->staticEval + 142 + 139 * lmrDepth + history / 64 <= alpha) continue; - // Prune moves with negative SEE (~20 Elo) + // Prune moves with negative SEE (~3 Elo) if (!pos.see_ge(move, Value(-21 * lmrDepth * lmrDepth - 21 * lmrDepth))) continue; } } - // Step 14. Extensions (~75 Elo) + // Step 14. Extensions (~66 Elo) - // Singular extension search (~70 Elo). If all moves but one fail low on a + // Singular extension search (~58 Elo). If all moves but one fail low on a // search of (alpha-s, beta-s), and just one fails high on (alpha, beta), // then that move is singular and should be extended. To verify this we do // a reduced search on all the other moves but the ttMove and if the @@ -1117,13 +1117,13 @@ moves_loop: // When in check, search starts here extension = -2; } - // Check extensions + // Check extensions (~1 Elo) else if ( givesCheck && depth > 6 && abs(ss->staticEval) > 100) extension = 1; - // Quiet ttMove extensions + // Quiet ttMove extensions (~0 Elo) else if ( PvNode && move == ttMove && move == ss->killers[0] @@ -1149,7 +1149,7 @@ moves_loop: // When in check, search starts here bool doDeeperSearch = false; - // Step 16. Late moves reduction / extension (LMR, ~200 Elo) + // Step 16. Late moves reduction / extension (LMR, ~98 Elo) // We use various heuristics for the sons of a node after the first son has // been searched. In general we would like to reduce them, but there are many // cases where we extend a son if it has good chances to be "interesting". @@ -1467,7 +1467,7 @@ moves_loop: // When in check, search starts here if ((ss->staticEval = bestValue = tte->eval()) == VALUE_NONE) ss->staticEval = bestValue = evaluate(pos); - // Can ttValue be used as a better position evaluation? + // ttValue can be used as a better position evaluation (~7 Elo) if ( ttValue != VALUE_NONE && (tte->bound() & (ttValue > bestValue ? BOUND_LOWER : BOUND_UPPER))) bestValue = ttValue; @@ -1522,7 +1522,7 @@ moves_loop: // When in check, search starts here moveCount++; - // Futility pruning and moveCount pruning + // Futility pruning and moveCount pruning (~5 Elo) if ( bestValue > VALUE_TB_LOSS_IN_MAX_PLY && !givesCheck && futilityBase > -VALUE_KNOWN_WIN @@ -1547,7 +1547,7 @@ moves_loop: // When in check, search starts here } } - // Do not search moves with negative SEE values + // Do not search moves with negative SEE values (~5 Elo) if ( bestValue > VALUE_TB_LOSS_IN_MAX_PLY && !pos.see_ge(move)) continue; @@ -1561,7 +1561,7 @@ moves_loop: // When in check, search starts here [pos.moved_piece(move)] [to_sq(move)]; - // Continuation history based pruning + // Continuation history based pruning (~2 Elo) if ( !captureOrPromotion && bestValue > VALUE_TB_LOSS_IN_MAX_PLY && (*contHist[0])[pos.moved_piece(move)][to_sq(move)] < CounterMovePruneThreshold From 0a6168089de8df15339e2c8f6604158d7434b678 Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Wed, 22 Dec 2021 07:54:10 +0300 Subject: [PATCH 058/105] Fall back to NNUE if classical evaluation is much lower than threshold The idea is that if classical eval returns a value much lower than the threshold of its usage it most likely means that position isn't that simple so we need the more precise NNUE evaluation. passed STC: https://tests.stockfishchess.org/tests/view/61bf3e7557a0d0f327c3c47a LLR: 2.95 (-2.94,2.94) <0.00,2.50> Total: 108072 W: 28007 L: 27604 D: 52461 Ptnml(0-2): 352, 12147, 28650, 12520, 367 passed LTC: https://tests.stockfishchess.org/tests/view/61c0581657a0d0f327c3fa0c LLR: 2.95 (-2.94,2.94) <0.50,3.00> Total: 155096 W: 40392 L: 39841 D: 74863 Ptnml(0-2): 88, 15983, 44843, 16558, 76 closes https://github.com/official-stockfish/Stockfish/pull/3869 bench 4310422 --- src/evaluate.cpp | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 28689f1d..8bc51695 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -1086,10 +1086,17 @@ Value Eval::evaluate(const Position& pos) { // Deciding between classical and NNUE eval (~10 Elo): for high PSQ imbalance we use classical, // but we switch to NNUE during long shuffling or with high material on the board. + bool classical = false; + if ( !useNNUE || abs(eg_value(pos.psq_score())) * 5 > (850 + pos.non_pawn_material() / 64) * (5 + pos.rule50_count())) + { v = Evaluation(pos).value(); // classical - else + classical = abs(v) >= 300; + } + + // If result of a classical evaluation is much lower than threshold fall back to NNUE + if (!classical && useNNUE) { int scale = 1136 + 20 * pos.non_pawn_material() / 1024; From 7d82f0d1f4e25892e1901d25cf5cf6f6a2606c2a Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Fri, 17 Dec 2021 19:34:30 +0100 Subject: [PATCH 059/105] Update default net to nn-ac07bd334b62.nnue Trained with essentially the same data as provided and used by Farseer (mbabigian) for the previous master net. T60T70wIsRightFarseerT60T74T75T76.binpack (99GB): ['T60T70wIsRightFarseer.binpack', 'farseerT74.binpack', 'farseerT75.binpack', 'farseerT76.binpack'] using the trainer branch tweakLR1PR (https://github.com/glinscott/nnue-pytorch/pull/158) and `--gpus 1 --threads 4 --num-workers 4 --batch-size 16384 --progress_bar_refresh_rate 300 --smart-fen-skipping --random-fen-skipping 12 --features=HalfKAv2_hm^ --lambda=1.00` options passed STC: LLR: 2.95 (-2.94,2.94) <0.00,2.50> Total: 108280 W: 28042 L: 27636 D: 52602 Ptnml(0-2): 328, 12382, 28401, 12614, 415 https://tests.stockfishchess.org/tests/view/61bcd8c257a0d0f327c34fbd passed LTC: LLR: 2.94 (-2.94,2.94) <0.50,3.00> Total: 259296 W: 66974 L: 66175 D: 126147 Ptnml(0-2): 146, 27096, 74452, 27721, 233 https://tests.stockfishchess.org/tests/view/61bda70957a0d0f327c37817 closes https://github.com/official-stockfish/Stockfish/pull/3870 Bench: 4633875 --- src/evaluate.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/evaluate.h b/src/evaluate.h index e258fdb6..d0c825eb 100644 --- a/src/evaluate.h +++ b/src/evaluate.h @@ -39,7 +39,7 @@ namespace Eval { // The default net name MUST follow the format nn-[SHA256 first 12 digits].nnue // for the build process (profile-build and fishtest) to work. Do not change the // name of the macro, as it is used in the Makefile. - #define EvalFileDefaultName "nn-4401e826ebcc.nnue" + #define EvalFileDefaultName "nn-ac07bd334b62.nnue" namespace NNUE { From 93b14a17d168e87e7f05fc09e3ba93e737b0757e Mon Sep 17 00:00:00 2001 From: bmc4 Date: Sat, 25 Dec 2021 08:54:16 -0300 Subject: [PATCH 060/105] Don't direct prune a move if it's a retake STC: LLR: 2.94 (-2.94,2.94) <0.00,2.50> Total: 36304 W: 9499 L: 9226 D: 17579 Ptnml(0-2): 96, 4102, 9508, 4325, 121 https://tests.stockfishchess.org/tests/view/61c7069ae68b2a714b6dca27 LTC: LLR: 2.95 (-2.94,2.94) <0.50,3.00> Total: 93824 W: 24478 L: 24068 D: 45278 Ptnml(0-2): 70, 9644, 27082, 10038, 78 https://tests.stockfishchess.org/tests/view/61c725fee68b2a714b6dcfa2 closes https://github.com/official-stockfish/Stockfish/pull/3871 Bench: 4106806 --- src/search.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index f5e9779c..a7629717 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1503,10 +1503,11 @@ moves_loop: // When in check, search starts here // to search the moves. Because the depth is <= 0 here, only captures, // queen promotions, and other checks (only if depth >= DEPTH_QS_CHECKS) // will be generated. + Square prevSq = to_sq((ss-1)->currentMove); MovePicker mp(pos, ttMove, depth, &thisThread->mainHistory, &thisThread->captureHistory, contHist, - to_sq((ss-1)->currentMove)); + prevSq); // Loop through the moves until no moves remain or a beta cutoff occurs while ((move = mp.next_move()) != MOVE_NONE) @@ -1525,6 +1526,7 @@ moves_loop: // When in check, search starts here // Futility pruning and moveCount pruning (~5 Elo) if ( bestValue > VALUE_TB_LOSS_IN_MAX_PLY && !givesCheck + && to_sq(move) != prevSq && futilityBase > -VALUE_KNOWN_WIN && type_of(move) != PROMOTION) { From 1066119083ffc8a697becbeb75a48f95add1a92d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Nicolet?= Date: Thu, 30 Dec 2021 11:23:40 +0100 Subject: [PATCH 061/105] Tweak optimism with complexity This patch increases the optimism bonus for "complex positions", where the complexity is measured as the absolute value of the difference between material and the sophisticated NNUE evaluation (idea by Joost VandeVondele). Also rename some variables in evaluate() while there. passed STC: LLR: 2.94 (-2.94,2.94) <0.00,2.50> Total: 88392 W: 23150 L: 22781 D: 42461 Ptnml(0-2): 318, 9961, 23257, 10354, 306 https://tests.stockfishchess.org/tests/view/61cbbedee68b2a714b6eb110 passed LTC: LLR: 2.93 (-2.94,2.94) <0.50,3.00> Total: 37848 W: 10043 L: 9766 D: 18039 Ptnml(0-2): 26, 3815, 10961, 4100, 22 https://tests.stockfishchess.org/tests/view/61cc0cc3e68b2a714b6ec28c Closes https://github.com/official-stockfish/Stockfish/pull/3875 Follow-up from https://github.com/official-stockfish/Stockfish/commit/a5a89b27c8e3225fb453d603bc4515d32bb351c3 Bench: 4125221 --- src/evaluate.cpp | 15 +++++++-------- 1 file changed, 7 insertions(+), 8 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 8bc51695..edff9185 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -1082,29 +1082,28 @@ make_v: Value Eval::evaluate(const Position& pos) { Value v; + bool useClassical = false; // Deciding between classical and NNUE eval (~10 Elo): for high PSQ imbalance we use classical, // but we switch to NNUE during long shuffling or with high material on the board. - - bool classical = false; - if ( !useNNUE || abs(eg_value(pos.psq_score())) * 5 > (850 + pos.non_pawn_material() / 64) * (5 + pos.rule50_count())) { v = Evaluation(pos).value(); // classical - classical = abs(v) >= 300; + useClassical = abs(v) >= 300; } // If result of a classical evaluation is much lower than threshold fall back to NNUE - if (!classical && useNNUE) + if (useNNUE && !useClassical) { - int scale = 1136 - + 20 * pos.non_pawn_material() / 1024; - Value nnue = NNUE::evaluate(pos, true); // NNUE + int scale = 1136 + 20 * pos.non_pawn_material() / 1024; Color stm = pos.side_to_move(); Value optimism = pos.this_thread()->optimism[stm]; + Value psq = (stm == WHITE ? 1 : -1) * eg_value(pos.psq_score()); + int complexity = abs(nnue - psq) / 256; + optimism *= (1 + complexity); v = (nnue + optimism) * scale / 1024 - optimism; if (pos.is_chess960()) From 061f98a9e3ae439fac13b4b2dda4be47977994b1 Mon Sep 17 00:00:00 2001 From: lonfom169 Date: Thu, 30 Dec 2021 22:50:20 -0300 Subject: [PATCH 062/105] Smooth out doDeeperSearch Adjust threshold based on the difference between newDepth and LMR depth. With more reduction, bigger fail-high is required in order to perform the deeper search. STC: LLR: 2.96 (-2.94,2.94) <0.00,2.50> Total: 93576 W: 24133 L: 23758 D: 45685 Ptnml(0-2): 260, 10493, 24935, 10812, 288 https://tests.stockfishchess.org/tests/view/61cbb5cee68b2a714b6eaf09 LTC: LLR: 2.94 (-2.94,2.94) <0.50,3.00> Total: 109280 W: 28198 L: 27754 D: 53328 Ptnml(0-2): 60, 11225, 31637, 11647, 71 https://tests.stockfishchess.org/tests/view/61cc03fee68b2a714b6ec091 closes https://github.com/official-stockfish/Stockfish/pull/3877 Bench: 4464723 --- src/search.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index a7629717..32a6ae61 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -550,7 +550,7 @@ namespace { if ( ss->ply > 10 && search_explosion(thisThread) == MUST_CALM_DOWN && depth > (ss-1)->depth) - depth = (ss-1)->depth; + depth = (ss-1)->depth; constexpr bool PvNode = nodeType != NonPV; constexpr bool rootNode = nodeType == Root; @@ -1212,7 +1212,7 @@ moves_loop: // When in check, search starts here // If the son is reduced and fails high it will be re-searched at full depth doFullDepthSearch = value > alpha && d < newDepth; - doDeeperSearch = value > alpha + 88; + doDeeperSearch = value > (alpha + 62 + 20 * (newDepth - d)); didLMR = true; } else @@ -1280,7 +1280,7 @@ moves_loop: // When in check, search starts here rm.pv.push_back(*m); // We record how often the best move has been changed in each iteration. - // This information is used for time management and LMR. In MultiPV mode, + // This information is used for time management. In MultiPV mode, // we must take care to only do this for the first PV line. if ( moveCount > 1 && !thisThread->pvIdx) From 0b41887527f1d7264ee5644dfa53e00ab64441b1 Mon Sep 17 00:00:00 2001 From: lonfom169 Date: Sat, 1 Jan 2022 14:09:08 -0300 Subject: [PATCH 063/105] Simplify away rangeReduction Remove rangeReduction, introduced in [#3717](https://github.com/official-stockfish/Stockfish/pull/3717), as it seemingly doesn't bring enough ELO anymore. It might be interesting to add new forms of reduction or tune the reduction formula in the future. STC: LLR: 2.95 (-2.94,2.94) <-2.25,0.25> Total: 45008 W: 12114 L: 11972 D: 20922 Ptnml(0-2): 174, 5031, 11952, 5173, 174 https://tests.stockfishchess.org/tests/view/61d08b7b069ca917749c9f6f LTC: LLR: 2.94 (-2.94,2.94) <-2.25,0.25> Total: 30792 W: 8235 L: 8086 D: 14471 Ptnml(0-2): 24, 3162, 8882, 3297, 31 https://tests.stockfishchess.org/tests/view/61d0a6ad069ca917749ca420 closes https://github.com/official-stockfish/Stockfish/pull/3878 Bench: 4048312 --- src/search.cpp | 14 ++++---------- 1 file changed, 4 insertions(+), 10 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 32a6ae61..2fd8245e 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -69,9 +69,9 @@ namespace { // Reductions lookup table, initialized at startup int Reductions[MAX_MOVES]; // [depth or moveNumber] - Depth reduction(bool i, Depth d, int mn, bool rangeReduction, Value delta, Value rootDelta) { + Depth reduction(bool i, Depth d, int mn, Value delta, Value rootDelta) { int r = Reductions[d] * Reductions[mn]; - return (r + 1358 - int(delta) * 1024 / int(rootDelta)) / 1024 + (!i && r > 904) + rangeReduction; + return (r + 1358 - int(delta) * 1024 / int(rootDelta)) / 1024 + (!i && r > 904); } constexpr int futility_move_count(bool improving, Depth depth) { @@ -938,8 +938,6 @@ namespace { moves_loop: // When in check, search starts here - int rangeReduction = 0; - // Step 11. A small Probcut idea, when we are in check (~0 Elo) probCutBeta = beta + 409; if ( ss->inCheck @@ -1026,7 +1024,7 @@ moves_loop: // When in check, search starts here moveCountPruning = moveCount >= futility_move_count(improving, depth); // Reduced depth of the next LMR search - int lmrDepth = std::max(newDepth - reduction(improving, depth, moveCount, rangeReduction > 2, delta, thisThread->rootDelta), 0); + int lmrDepth = std::max(newDepth - reduction(improving, depth, moveCount, delta, thisThread->rootDelta), 0); if ( captureOrPromotion || givesCheck) @@ -1159,7 +1157,7 @@ moves_loop: // When in check, search starts here || !captureOrPromotion || (cutNode && (ss-1)->moveCount > 1))) { - Depth r = reduction(improving, depth, moveCount, rangeReduction > 2, delta, thisThread->rootDelta); + Depth r = reduction(improving, depth, moveCount, delta, thisThread->rootDelta); // Decrease reduction at some PvNodes (~2 Elo) if ( PvNode @@ -1206,10 +1204,6 @@ moves_loop: // When in check, search starts here value = -search(pos, ss+1, -(alpha+1), -alpha, d, true); - // Range reductions (~3 Elo) - if (ss->staticEval - value < 30 && depth > 7) - rangeReduction++; - // If the son is reduced and fails high it will be re-searched at full depth doFullDepthSearch = value > alpha && d < newDepth; doDeeperSearch = value > (alpha + 62 + 20 * (newDepth - d)); From ad926d34c0105d523bfa5cb92cbcf9f337d54c08 Mon Sep 17 00:00:00 2001 From: Brad Knox <64992190+bknox83@users.noreply.github.com> Date: Mon, 3 Jan 2022 20:33:26 -0600 Subject: [PATCH 064/105] Update copyright years Happy New Year! closes https://github.com/official-stockfish/Stockfish/pull/3881 No functional change --- src/Makefile | 2 +- src/benchmark.cpp | 2 +- src/bitbase.cpp | 2 +- src/bitboard.cpp | 2 +- src/bitboard.h | 2 +- src/endgame.cpp | 2 +- src/endgame.h | 2 +- src/evaluate.cpp | 2 +- src/evaluate.h | 2 +- src/main.cpp | 2 +- src/material.cpp | 2 +- src/material.h | 2 +- src/misc.cpp | 2 +- src/misc.h | 2 +- src/movegen.cpp | 2 +- src/movegen.h | 2 +- src/movepick.cpp | 2 +- src/movepick.h | 2 +- src/nnue/evaluate_nnue.cpp | 2 +- src/nnue/evaluate_nnue.h | 2 +- src/nnue/features/half_ka_v2_hm.cpp | 2 +- src/nnue/features/half_ka_v2_hm.h | 2 +- src/nnue/layers/affine_transform.h | 2 +- src/nnue/layers/clipped_relu.h | 2 +- src/nnue/layers/input_slice.h | 2 +- src/nnue/nnue_accumulator.h | 2 +- src/nnue/nnue_architecture.h | 2 +- src/nnue/nnue_common.h | 2 +- src/nnue/nnue_feature_transformer.h | 2 +- src/pawns.cpp | 2 +- src/pawns.h | 2 +- src/position.cpp | 2 +- src/position.h | 2 +- src/psqt.cpp | 2 +- src/psqt.h | 2 +- src/search.cpp | 2 +- src/search.h | 2 +- src/simd.h | 2 +- src/syzygy/tbprobe.cpp | 2 +- src/syzygy/tbprobe.h | 2 +- src/thread.cpp | 2 +- src/thread.h | 2 +- src/thread_win32_osx.h | 2 +- src/timeman.cpp | 2 +- src/timeman.h | 2 +- src/tt.cpp | 2 +- src/tt.h | 2 +- src/tune.cpp | 2 +- src/tune.h | 2 +- src/types.h | 2 +- src/uci.cpp | 2 +- src/uci.h | 2 +- src/ucioption.cpp | 2 +- 53 files changed, 53 insertions(+), 53 deletions(-) diff --git a/src/Makefile b/src/Makefile index f00df79f..406f029f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -1,5 +1,5 @@ # Stockfish, a UCI chess playing engine derived from Glaurung 2.1 -# Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) +# Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) # # Stockfish is free software: you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by diff --git a/src/benchmark.cpp b/src/benchmark.cpp index 7945a453..02ff2f9d 100644 --- a/src/benchmark.cpp +++ b/src/benchmark.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/bitbase.cpp b/src/bitbase.cpp index 27bf4095..84300baf 100644 --- a/src/bitbase.cpp +++ b/src/bitbase.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/bitboard.cpp b/src/bitboard.cpp index 6b84b51e..fd0ba235 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/bitboard.h b/src/bitboard.h index b29f3e24..2b6e2a69 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/endgame.cpp b/src/endgame.cpp index a44d3a1c..e773e7a9 100644 --- a/src/endgame.cpp +++ b/src/endgame.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/endgame.h b/src/endgame.h index 146111b9..e79f696f 100644 --- a/src/endgame.h +++ b/src/endgame.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/evaluate.cpp b/src/evaluate.cpp index edff9185..ab71fa67 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/evaluate.h b/src/evaluate.h index d0c825eb..57a7687d 100644 --- a/src/evaluate.h +++ b/src/evaluate.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/main.cpp b/src/main.cpp index 62e0ed52..fad0ef84 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/material.cpp b/src/material.cpp index 9d17af20..1567358a 100644 --- a/src/material.cpp +++ b/src/material.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/material.h b/src/material.h index 26535a53..3ca169ce 100644 --- a/src/material.h +++ b/src/material.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/misc.cpp b/src/misc.cpp index b46786df..41c59b3f 100644 --- a/src/misc.cpp +++ b/src/misc.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/misc.h b/src/misc.h index 062b420a..688d00e7 100644 --- a/src/misc.h +++ b/src/misc.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/movegen.cpp b/src/movegen.cpp index 5095bb74..c7a3c29b 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/movegen.h b/src/movegen.h index 3f895f05..bbb35b39 100644 --- a/src/movegen.h +++ b/src/movegen.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/movepick.cpp b/src/movepick.cpp index 6aa1954b..694b9222 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/movepick.h b/src/movepick.h index 426bac89..e2cbfcde 100644 --- a/src/movepick.h +++ b/src/movepick.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/nnue/evaluate_nnue.cpp b/src/nnue/evaluate_nnue.cpp index a534753a..862b2003 100644 --- a/src/nnue/evaluate_nnue.cpp +++ b/src/nnue/evaluate_nnue.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/nnue/evaluate_nnue.h b/src/nnue/evaluate_nnue.h index c7fa4a96..2e4f1f50 100644 --- a/src/nnue/evaluate_nnue.h +++ b/src/nnue/evaluate_nnue.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/nnue/features/half_ka_v2_hm.cpp b/src/nnue/features/half_ka_v2_hm.cpp index 6face217..07a1d7a1 100644 --- a/src/nnue/features/half_ka_v2_hm.cpp +++ b/src/nnue/features/half_ka_v2_hm.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/nnue/features/half_ka_v2_hm.h b/src/nnue/features/half_ka_v2_hm.h index c7b1a68d..1e6da0bf 100644 --- a/src/nnue/features/half_ka_v2_hm.h +++ b/src/nnue/features/half_ka_v2_hm.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/nnue/layers/affine_transform.h b/src/nnue/layers/affine_transform.h index 11038d69..4e85a5fe 100644 --- a/src/nnue/layers/affine_transform.h +++ b/src/nnue/layers/affine_transform.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/nnue/layers/clipped_relu.h b/src/nnue/layers/clipped_relu.h index c6f3ccad..0da5e821 100644 --- a/src/nnue/layers/clipped_relu.h +++ b/src/nnue/layers/clipped_relu.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/nnue/layers/input_slice.h b/src/nnue/layers/input_slice.h index b6bf1727..8f526b74 100644 --- a/src/nnue/layers/input_slice.h +++ b/src/nnue/layers/input_slice.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/nnue/nnue_accumulator.h b/src/nnue/nnue_accumulator.h index d41ecf95..600483b5 100644 --- a/src/nnue/nnue_accumulator.h +++ b/src/nnue/nnue_accumulator.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/nnue/nnue_architecture.h b/src/nnue/nnue_architecture.h index 193a197d..8867fac7 100644 --- a/src/nnue/nnue_architecture.h +++ b/src/nnue/nnue_architecture.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/nnue/nnue_common.h b/src/nnue/nnue_common.h index 74eaae17..1bce00ae 100644 --- a/src/nnue/nnue_common.h +++ b/src/nnue/nnue_common.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/nnue/nnue_feature_transformer.h b/src/nnue/nnue_feature_transformer.h index 4f6a174a..f4024dce 100644 --- a/src/nnue/nnue_feature_transformer.h +++ b/src/nnue/nnue_feature_transformer.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/pawns.cpp b/src/pawns.cpp index 70fb6f23..6e509133 100644 --- a/src/pawns.cpp +++ b/src/pawns.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/pawns.h b/src/pawns.h index 124619d6..af0370fc 100644 --- a/src/pawns.h +++ b/src/pawns.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/position.cpp b/src/position.cpp index ae1da017..ec9229ea 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/position.h b/src/position.h index 9f694a79..8dbf1493 100644 --- a/src/position.h +++ b/src/position.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/psqt.cpp b/src/psqt.cpp index 33a3e00c..ca5664c2 100644 --- a/src/psqt.cpp +++ b/src/psqt.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/psqt.h b/src/psqt.h index 7abb1483..4ee0e379 100644 --- a/src/psqt.h +++ b/src/psqt.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/search.cpp b/src/search.cpp index 2fd8245e..86af3918 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/search.h b/src/search.h index 7a5d5bdf..806295a1 100644 --- a/src/search.h +++ b/src/search.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/simd.h b/src/simd.h index ffa54d96..7b9e8fb2 100644 --- a/src/simd.h +++ b/src/simd.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/syzygy/tbprobe.cpp b/src/syzygy/tbprobe.cpp index 41e867c0..a1315244 100644 --- a/src/syzygy/tbprobe.cpp +++ b/src/syzygy/tbprobe.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/syzygy/tbprobe.h b/src/syzygy/tbprobe.h index cf61b767..c2917fef 100644 --- a/src/syzygy/tbprobe.h +++ b/src/syzygy/tbprobe.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/thread.cpp b/src/thread.cpp index 099efbad..30177a39 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/thread.h b/src/thread.h index 6bc1be65..a6b0b5a0 100644 --- a/src/thread.h +++ b/src/thread.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/thread_win32_osx.h b/src/thread_win32_osx.h index a21674cc..77d1c3c7 100644 --- a/src/thread_win32_osx.h +++ b/src/thread_win32_osx.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/timeman.cpp b/src/timeman.cpp index 69d1c96f..0400401e 100644 --- a/src/timeman.cpp +++ b/src/timeman.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/timeman.h b/src/timeman.h index b1878d65..a86f0769 100644 --- a/src/timeman.h +++ b/src/timeman.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/tt.cpp b/src/tt.cpp index 4af6c9f1..c7118aea 100644 --- a/src/tt.cpp +++ b/src/tt.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/tt.h b/src/tt.h index d915d92e..03fe3e14 100644 --- a/src/tt.h +++ b/src/tt.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/tune.cpp b/src/tune.cpp index ac91b606..a885845f 100644 --- a/src/tune.cpp +++ b/src/tune.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/tune.h b/src/tune.h index 53d52a65..75ab484a 100644 --- a/src/tune.h +++ b/src/tune.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/types.h b/src/types.h index 02cd19de..a3a873fa 100644 --- a/src/types.h +++ b/src/types.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/uci.cpp b/src/uci.cpp index b3738a4a..741241b3 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/uci.h b/src/uci.h index d3160109..5bb24a4e 100644 --- a/src/uci.h +++ b/src/uci.h @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by diff --git a/src/ucioption.cpp b/src/ucioption.cpp index 0cafd3e9..922fa34f 100644 --- a/src/ucioption.cpp +++ b/src/ucioption.cpp @@ -1,6 +1,6 @@ /* Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2021 The Stockfish developers (see AUTHORS file) + Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) Stockfish is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by From 2efda17c2ac4253dec7c566268363f4dfd391b02 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ste=CC=81phane=20Nicolet?= Date: Fri, 7 Jan 2022 07:55:50 +0100 Subject: [PATCH 065/105] Update AUTHORS and CPU contributors files closes https://github.com/official-stockfish/Stockfish/pull/3882 No functional change --- AUTHORS | 1 + Top CPU Contributors.txt | 118 ++++++++++++++++++++------------------- 2 files changed, 61 insertions(+), 58 deletions(-) diff --git a/AUTHORS b/AUTHORS index 35ccdaf5..d7e6dc98 100644 --- a/AUTHORS +++ b/AUTHORS @@ -132,6 +132,7 @@ Michael Whiteley (protonspring) Michel Van den Bergh (vdbergh) Miguel Lahoz (miguel-l) Mikael Bäckman (mbootsector) +Mike Babigian (Farseer) Mira Miroslav FontĂ¡n (Hexik) Moez Jellouli (MJZ1977) diff --git a/Top CPU Contributors.txt b/Top CPU Contributors.txt index f0ec51f9..718d7cca 100644 --- a/Top CPU Contributors.txt +++ b/Top CPU Contributors.txt @@ -1,68 +1,69 @@ -Contributors to Fishtest with >10,000 CPU hours, as of 2021-12-11. +Contributors to Fishtest with >10,000 CPU hours, as of 2022-01-08. Thank you! Username CPU Hours Games played ------------------------------------------------------------------ -noobpwnftw 29832955 2061725095 -mlang 2345848 162775694 -dew 1559902 93935940 -technologov 1154365 43136020 -grandphish2 988545 60725563 +noobpwnftw 30323785 2111752181 +mlang 2597136 178003354 +dew 1598255 95747056 +technologov 1395130 59347018 +grandphish2 1028906 63396841 tvijlbrief 795993 51894442 -TueRens 716909 45503672 +TueRens 737922 46359276 +okrout 719183 57150314 mibere 703840 46867607 -JojoM 675708 41046762 -okrout 648513 49953162 -linrock 563226 16184599 -pemo 520578 26816487 -gvreuls 501232 32662374 -cw 495103 33171295 -fastgm 476917 28660004 +JojoM 689134 42001146 +linrock 594355 16779359 +pemo 575248 28386103 +gvreuls 509219 33205908 +cw 500695 33575803 +fastgm 479238 28830588 crunchy 427035 27344275 -CSU_Dynasty 407300 27580858 -ctoks 386452 25757397 -oz 343309 25441096 +CSU_Dynasty 410969 27877556 +ctoks 393901 26299629 +oz 354661 26331020 Fisherman 327231 21829379 -velislav 320318 20642978 -bcross 319459 22485737 -leszek 277442 17495865 -Dantist 229980 14568674 -mgrabiak 225684 14774260 +bcross 325119 22871639 +velislav 320581 20663382 +leszek 291605 18475167 +Dantist 239411 15236750 +mgrabiak 229336 15004308 glinscott 217799 13780820 +robal 211837 13563250 nordlandia 211692 13484886 -robal 209847 13427680 -drabel 200340 13727458 +drabel 200377 13730626 bking_US 198894 11876016 Thanar 179852 12365359 -vdv 175274 9889046 -mhoram 166293 10796647 +vdv 175535 9904264 +mhoram 173134 11257113 spams 157128 10319326 marrco 150300 9402229 sqrt2 147963 9724586 -vdbergh 137186 8938965 +vdbergh 137425 8954767 CoffeeOne 137100 5024116 malala 136182 8002293 xoto 133759 9159372 -davar 122092 7960001 +davar 122113 7961971 dsmith 122059 7570238 amicic 119659 7937885 +rpngn 118952 8100045 Data 113305 8220352 BrunoBanani 112960 7436849 -rpngn 109031 7392547 CypressChess 108321 7759588 MaZePallas 102823 6633619 sterni1971 100532 5880772 sunu 100167 7040199 ElbertoOne 99028 7023771 -skiminki 98121 6478170 +skiminki 98123 6478402 +DesolatedDodo 93686 6139198 brabos 92118 6186135 +cuistot 90357 5350988 psk 89957 5984901 -cuistot 88420 5225234 -DesolatedDodo 88356 5779482 -racerschmacer 85711 6119610 +racerschmacer 85712 6119648 Vizvezdenec 83761 5344740 0x3C33 82614 5271253 BRAVONE 81239 5054681 +sschnee 78091 4678078 nssy 76497 5259388 teddybaer 75125 5407666 Pking_cda 73776 5293873 @@ -70,59 +71,59 @@ jromang 72192 5057715 solarlight 70517 5028306 dv8silencer 70287 3883992 Bobo1239 68515 4652287 +zeryl 68203 4516139 manap 66273 4121774 -sschnee 64563 3633680 tinker 64333 4268790 -zeryl 63290 4179159 +yurikvelo 61692 4262042 qurashee 61208 3429862 -yurikvelo 60387 4169900 robnjr 57262 4053117 Freja 56938 3733019 ttruscott 56010 3680085 rkl 55132 4164467 +Wolfgang 54087 3415872 renouve 53811 3501516 finfish 51360 3370515 eva42 51272 3599691 -Wolfgang 51248 3218932 -eastorwest 50311 3409935 +eastorwest 51055 3451203 rap 49985 3219146 pb00067 49727 3298270 +Spprtr 48260 3141959 bigpen0r 47667 3336927 ronaldjerum 47654 3240695 MaxKlaxxMiner 47584 2972142 biffhero 46564 3111352 -Spprtr 45877 2995437 Fifis 45843 3088497 VoyagerOne 45476 3452465 speedycpu 43842 3003273 jbwiebe 43305 2805433 +megaman7de 43042 2823256 Antihistamine 41788 2761312 mhunt 41735 2691355 -megaman7de 40060 2625050 homyur 39893 2850481 gri 39871 2515779 -oryx 38860 2976488 +oryx 38867 2976992 SC 37299 2731694 +Garf 37213 2986270 csnodgrass 36207 2688994 jmdana 36157 2210661 -Garf 36113 2897580 strelock 34716 2074055 EthanOConnor 33370 2090311 slakovv 32915 2021889 +Calis007 32024 2163604 manapbk 30987 1810399 DMBK 30675 2383552 Prcuvu 30377 2170122 anst 30301 2190091 +armo9494 30198 2438202 jkiiski 30136 1904470 +tolkki963 29918 1822290 hyperbolic.tom 29840 2017394 chuckstablers 29659 2093438 Pyafue 29650 1902349 -tolkki963 28171 1716386 +gopeto 28881 1896862 OuaisBla 27636 1578800 -armo9494 27224 2221042 chriswk 26902 1868317 achambord 26582 1767323 -gopeto 26355 1717722 Patrick_G 26276 1801617 yorkman 26193 1992080 SFTUser 25182 1675689 @@ -135,8 +136,8 @@ JanErik 23408 1703875 Isidor 23388 1680691 Norabor 23339 1602636 cisco2015 22897 1762669 +Ente 22810 1628234 Zirie 22542 1472937 -Ente 22486 1606268 team-oh 22272 1636708 MazeOfGalious 21978 1629593 sg4032 21947 1643265 @@ -151,10 +152,11 @@ horst.prack 20878 1465656 j3corre 20405 941444 Adrian.Schmidt123 20316 1281436 wei 19973 1745989 +belzedar94 19818 1434252 +user213718 19608 1334650 rstoesser 19569 1293588 eudhan 19274 1283717 vulcan 18871 1729392 -user213718 18590 1271128 jundery 18445 1115855 iisiraider 18247 1101015 ville 17883 1384026 @@ -163,52 +165,53 @@ purplefishies 17595 1092533 dju 17353 978595 DragonLord 17014 1162790 IgorLeMasson 16064 1147232 +Roady 15677 1121476 ako027ako 15671 1173203 +kdave 15539 1160356 Nikolay.IT 15154 1068349 Andrew Grant 15114 895539 OssumOpossum 14857 1007129 +spcc 14838 1034050 Karby 14808 867120 enedene 14476 905279 -jsys14 14318 843704 +fishtester 14411 1016252 +jsys14 14340 844792 bpfliegel 14298 884523 +AndreasKrug 14096 1126301 mpx86 14019 759568 jpulman 13982 870599 -kdave 13933 1045550 +Ulysses 13977 1073410 crocogoat 13803 1117422 joster 13794 950160 Nesa92 13786 1114691 mbeier 13650 1044928 -AndreasKrug 13624 1090613 Hjax 13535 915487 Dark_wizzie 13422 1007152 -Ulysses 13392 1021264 -Calis007 13267 873236 Rudolphous 13244 883140 -spcc 13085 917006 Machariel 13010 863104 mabichito 12903 749391 thijsk 12886 722107 AdrianSA 12860 804972 Flopzee 12698 894821 +infinigon 12638 933684 fatmurphy 12547 853210 scuzzi 12511 845761 SapphireBrand 12416 969604 modolief 12386 896470 -fishtester 12320 873882 Farseer 12249 694108 pgontarz 12151 848794 stocky 11954 699440 mschmidt 11941 803401 Maxim 11543 836024 infinity 11470 727027 +pirt 11434 889369 aga 11409 695071 torbjo 11395 729145 -pirt 11392 886291 Thomas A. Anderson 11372 732094 savage84 11358 670860 FormazChar 11304 847663 +dbernier 11274 806566 d64 11263 789184 -dbernier 11258 805102 MooTheCow 11237 720174 snicolet 11106 869170 ali-al-zhrani 11098 768494 @@ -217,7 +220,6 @@ Cubox 10621 826448 michaelrpg 10509 739239 OIVAS7572 10420 995586 dzjp 10343 732529 -infinigon 10319 776158 -Garruk 10314 702629 +Garruk 10332 703905 ols 10259 570669 lbraesch 10252 647825 From 9ad0ea73825bf463e842fb1fd41b5acaa8a1cfe1 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Thu, 6 Jan 2022 07:44:41 +0100 Subject: [PATCH 066/105] Tune a few parameters related to evaluation based on a SPSA tune (using Autoselect) https://tests.stockfishchess.org/tests/view/61d5aa63a314fed318a57046 passed STC: LLR: 2.93 (-2.94,2.94) <0.00,2.50> Total: 61960 W: 16640 L: 16316 D: 29004 Ptnml(0-2): 278, 6934, 16204, 7314, 250 https://tests.stockfishchess.org/tests/view/61d7fe4af5fd40f357469a8d passed LTC: LLR: 2.97 (-2.94,2.94) <0.50,3.00> Total: 79408 W: 21994 L: 21618 D: 35796 Ptnml(0-2): 106, 7887, 23331, 8285, 95 https://tests.stockfishchess.org/tests/view/61d836b7f5fd40f35746a3d5 closes https://github.com/official-stockfish/Stockfish/pull/3883 Bench: 4266621 --- src/evaluate.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index ab71fa67..4f3843f8 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -192,8 +192,8 @@ using namespace Trace; namespace { // Threshold for lazy and space evaluation - constexpr Value LazyThreshold1 = Value(3130); - constexpr Value LazyThreshold2 = Value(2204); + constexpr Value LazyThreshold1 = Value(3631); + constexpr Value LazyThreshold2 = Value(2084); constexpr Value SpaceThreshold = Value(11551); // KingAttackWeights[PieceType] contains king attack weights by piece type @@ -1087,10 +1087,10 @@ Value Eval::evaluate(const Position& pos) { // Deciding between classical and NNUE eval (~10 Elo): for high PSQ imbalance we use classical, // but we switch to NNUE during long shuffling or with high material on the board. if ( !useNNUE - || abs(eg_value(pos.psq_score())) * 5 > (850 + pos.non_pawn_material() / 64) * (5 + pos.rule50_count())) + || abs(eg_value(pos.psq_score())) * 5 > (849 + pos.non_pawn_material() / 64) * (5 + pos.rule50_count())) { v = Evaluation(pos).value(); // classical - useClassical = abs(v) >= 300; + useClassical = abs(v) >= 298; } // If result of a classical evaluation is much lower than threshold fall back to NNUE @@ -1101,9 +1101,9 @@ Value Eval::evaluate(const Position& pos) { Color stm = pos.side_to_move(); Value optimism = pos.this_thread()->optimism[stm]; Value psq = (stm == WHITE ? 1 : -1) * eg_value(pos.psq_score()); - int complexity = abs(nnue - psq) / 256; + int complexity = 35 * abs(nnue - psq) / 256; - optimism *= (1 + complexity); + optimism = optimism * (44 + complexity) / 32; v = (nnue + optimism) * scale / 1024 - optimism; if (pos.is_chess960()) @@ -1111,7 +1111,7 @@ Value Eval::evaluate(const Position& pos) { } // Damp down the evaluation linearly when shuffling - v = v * (207 - pos.rule50_count()) / 207; + v = v * (208 - pos.rule50_count()) / 208; // Guarantee evaluation does not hit the tablebase range v = std::clamp(v, VALUE_TB_LOSS_IN_MAX_PLY + 1, VALUE_TB_WIN_IN_MAX_PLY - 1); From c5a280c0125b71cdf43bf326551bc95bb4dbc014 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Fri, 7 Jan 2022 22:57:09 +0100 Subject: [PATCH 067/105] Tune FRC trapped Bishop patch now that fishtest can deal with FRC, retune this correction. Add an additional fen to bench with cornered B and N. passed STC: LLR: 2.95 (-2.94,2.94) <0.00,2.50> Total: 49672 W: 7358 L: 7082 D: 35232 Ptnml(0-2): 241, 4329, 15458, 4529, 279 https://tests.stockfishchess.org/tests/view/61d8b7bf9fea7913d9c63cb7 passed LTC: LLR: 2.95 (-2.94,2.94) <0.50,3.00> Total: 86688 W: 8308 L: 8007 D: 70373 Ptnml(0-2): 92, 4943, 32989, 5212, 108 https://tests.stockfishchess.org/tests/view/61d92dcb9fea7913d9c650ad closes https://github.com/official-stockfish/Stockfish/pull/3884 Bench: 4326560 --- src/benchmark.cpp | 1 + src/evaluate.cpp | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/benchmark.cpp b/src/benchmark.cpp index 02ff2f9d..e1c025ad 100644 --- a/src/benchmark.cpp +++ b/src/benchmark.cpp @@ -87,6 +87,7 @@ const vector Defaults = { // Chess 960 "setoption name UCI_Chess960 value true", "bbqnnrkr/pppppppp/8/8/8/8/PPPPPPPP/BBQNNRKR w HFhf - 0 1 moves g2g3 d7d5 d2d4 c8h3 c1g5 e8d6 g5e7 f7f6", + "nqbnrkrb/pppppppp/8/8/8/8/PPPPPPPP/NQBNRKRB w KQkq - 0 1", "setoption name UCI_Chess960 value false" }; diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 4f3843f8..a5c049a8 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -1069,8 +1069,8 @@ make_v: && pos.piece_on(SQ_G7) == B_PAWN) correction += CorneredBishop; - return pos.side_to_move() == WHITE ? Value(5 * correction) - : -Value(5 * correction); + return pos.side_to_move() == WHITE ? Value(3 * correction) + : -Value(3 * correction); } } // namespace Eval From 44b1ba89a95f394f3e180eb508f2d7798417c86e Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Mon, 10 Jan 2022 21:29:25 +0300 Subject: [PATCH 068/105] Adjust pruning constants This patch is a modification of original tuning done by vondele that failed yellow. Value differences are divided by 2. Passed STC https://tests.stockfishchess.org/tests/view/61d918239fea7913d9c64cdf LLR: 2.94 (-2.94,2.94) <0.00,2.50> Total: 98968 W: 26248 L: 25858 D: 46862 Ptnml(0-2): 392, 11085, 26156, 11443, 408 Passed LTC https://tests.stockfishchess.org/tests/view/61d99e3c9fea7913d9c663e4 LLR: 2.95 (-2.94,2.94) <0.50,3.00> Total: 215232 W: 58191 L: 57492 D: 99549 Ptnml(0-2): 271, 22124, 62138, 22801, 282 closes https://github.com/official-stockfish/Stockfish/pull/3885 bench 4572746 --- src/search.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 86af3918..58873c89 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1040,7 +1040,7 @@ moves_loop: // When in check, search starts here continue; // SEE based pruning (~9 Elo) - if (!pos.see_ge(move, Value(-218) * depth)) + if (!pos.see_ge(move, Value(-217) * depth)) continue; } else @@ -1051,7 +1051,7 @@ moves_loop: // When in check, search starts here // Continuation history based pruning (~2 Elo) if ( lmrDepth < 5 - && history < -3000 * depth + 3000) + && history < -3875 * (depth - 1)) continue; history += thisThread->mainHistory[us][from_to(move)]; @@ -1059,7 +1059,7 @@ moves_loop: // When in check, search starts here // Futility pruning: parent node (~9 Elo) if ( !ss->inCheck && lmrDepth < 8 - && ss->staticEval + 142 + 139 * lmrDepth + history / 64 <= alpha) + && ss->staticEval + 138 + 137 * lmrDepth + history / 64 <= alpha) continue; // Prune moves with negative SEE (~3 Elo) From c5d45d3220f74045aff249c47abd91d8d663b748 Mon Sep 17 00:00:00 2001 From: pschneider1968 <36973164+pschneider1968@users.noreply.github.com> Date: Mon, 27 Dec 2021 21:16:04 +0100 Subject: [PATCH 069/105] Fix Makefile for compilation with clang on Windows use static compilation and added exclusion of -latomic for Clang/MSYS2 as per ppigazzini's suggestion fixes #3872 closes https://github.com/official-stockfish/Stockfish/pull/3873 No functional change --- src/Makefile | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/Makefile b/src/Makefile index 406f029f..0e889888 100644 --- a/src/Makefile +++ b/src/Makefile @@ -404,12 +404,14 @@ ifeq ($(COMP),clang) ifneq ($(KERNEL),Darwin) ifneq ($(KERNEL),OpenBSD) ifneq ($(KERNEL),FreeBSD) + ifneq ($(findstring MINGW,$(KERNEL)),MINGW) ifneq ($(RTLIB),compiler-rt) LDFLAGS += -latomic endif endif endif endif + endif ifeq ($(arch),$(filter $(arch),armv7 armv8)) ifeq ($(OS),Android) @@ -420,6 +422,11 @@ ifeq ($(COMP),clang) CXXFLAGS += -m$(bits) LDFLAGS += -m$(bits) endif + + ifeq ($(findstring MINGW,$(KERNEL)),MINGW) + LDFLAGS += -static + endif + endif ifeq ($(KERNEL),Darwin) From 7678d63cf2323e51c01e60cdff4ac3d685313790 Mon Sep 17 00:00:00 2001 From: Rui Coelho Date: Thu, 13 Jan 2022 18:30:53 +0000 Subject: [PATCH 070/105] Use complexity in search This patch uses the complexity measure (from #3875) as a heuristic for null move pruning. Hopefully, there may be room to use it in other pruning techniques. I would like to thank vondele and locutus2 for the feedback and suggestions during testing. Passed STC LLR: 2.95 (-2.94,2.94) <0.00,2.50> Total: 35000 W: 9624 L: 9347 D: 16029 Ptnml(0-2): 156, 3894, 9137, 4143, 170 https://tests.stockfishchess.org/tests/view/61dda784c65bf87d6c45ab80 Passed LTC LLR: 2.94 (-2.94,2.94) <0.50,3.00> Total: 230776 W: 64227 L: 63454 D: 103095 Ptnml(0-2): 1082, 23100, 66380, 23615, 1211 https://tests.stockfishchess.org/tests/view/61ddd0cf3ddbc32543e72c2b Closes https://github.com/official-stockfish/Stockfish/pull/3890 Bench: 4464962 --- AUTHORS | 1 + src/search.cpp | 6 ++++-- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/AUTHORS b/AUTHORS index d7e6dc98..f49c1db0 100644 --- a/AUTHORS +++ b/AUTHORS @@ -166,6 +166,7 @@ Rodrigo Exterckötter Tjäder Ron Britvich (Britvich) Ronald de Man (syzygy1, syzygy) rqs +Rui Coelho (ruicoelhopedro) Ryan Schmitt Ryan Takker Sami Kiminki (skiminki) diff --git a/src/search.cpp b/src/search.cpp index 58873c89..c81496d1 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -589,7 +589,7 @@ namespace { bool givesCheck, improving, didLMR, priorCapture; bool captureOrPromotion, doFullDepthSearch, moveCountPruning, ttCapture; Piece movedPiece; - int moveCount, captureCount, quietCount, bestMoveCount, improvement; + int moveCount, captureCount, quietCount, bestMoveCount, improvement, complexity; // Step 1. Initialize node ss->inCheck = pos.checkers(); @@ -760,6 +760,7 @@ namespace { ss->staticEval = eval = VALUE_NONE; improving = false; improvement = 0; + complexity = 0; goto moves_loop; } else if (ss->ttHit) @@ -803,6 +804,7 @@ namespace { : 200; improving = improvement > 0; + complexity = abs(ss->staticEval - (us == WHITE ? eg_value(pos.psq_score()) : -eg_value(pos.psq_score()))); // Step 7. Futility pruning: child node (~25 Elo). // The depth condition is important for mate finding. @@ -818,7 +820,7 @@ namespace { && (ss-1)->statScore < 23767 && eval >= beta && eval >= ss->staticEval - && ss->staticEval >= beta - 20 * depth - improvement / 15 + 204 + && ss->staticEval >= beta - 20 * depth - improvement / 15 + 204 + complexity / 25 && !excludedMove && pos.non_pawn_material(us) && (ss->ply >= thisThread->nmpMinPly || us != thisThread->nmpColor)) From d11101e4c6cd6aafca06e07d24e1c7026c92f6e7 Mon Sep 17 00:00:00 2001 From: proukornew Date: Fri, 17 Dec 2021 01:30:23 +0300 Subject: [PATCH 071/105] Improve logic on mingw There is no need to point g++, if we explicitly choose mingw. Now for cygwin: make COMP=mingw ARCH=x86-64-modern build closes https://github.com/official-stockfish/Stockfish/pull/3860 No functional change --- src/Makefile | 22 +++++++++------------- 1 file changed, 9 insertions(+), 13 deletions(-) diff --git a/src/Makefile b/src/Makefile index 0e889888..90e596af 100644 --- a/src/Makefile +++ b/src/Makefile @@ -368,22 +368,18 @@ endif ifeq ($(COMP),mingw) comp=mingw - ifeq ($(KERNEL),Linux) - ifeq ($(bits),64) - ifeq ($(shell which x86_64-w64-mingw32-c++-posix),) - CXX=x86_64-w64-mingw32-c++ - else - CXX=x86_64-w64-mingw32-c++-posix - endif + ifeq ($(bits),64) + ifeq ($(shell which x86_64-w64-mingw32-c++-posix 2> /dev/null),) + CXX=x86_64-w64-mingw32-c++ else - ifeq ($(shell which i686-w64-mingw32-c++-posix),) - CXX=i686-w64-mingw32-c++ - else - CXX=i686-w64-mingw32-c++-posix - endif + CXX=x86_64-w64-mingw32-c++-posix endif else - CXX=g++ + ifeq ($(shell which i686-w64-mingw32-c++-posix 2> /dev/null),) + CXX=i686-w64-mingw32-c++ + else + CXX=i686-w64-mingw32-c++-posix + endif endif CXXFLAGS += -pedantic -Wextra -Wshadow From 2b0372319d2a6797c49cb24dca5da221a669e36a Mon Sep 17 00:00:00 2001 From: Rui Coelho Date: Mon, 17 Jan 2022 16:51:20 +0000 Subject: [PATCH 072/105] Use average complexity for time management This patch is a variant of the idea by locutus2 (https://tests.stockfishchess.org/tests/view/61e1f24cb1f9959fe5d88168) to adjust the total time depending on the average complexity of the position. Passed STC LLR: 2.94 (-2.94,2.94) <0.00,2.50> Total: 39664 W: 10765 L: 10487 D: 18412 Ptnml(0-2): 162, 4213, 10837, 4425, 195 https://tests.stockfishchess.org/tests/view/61e2df8b65a644da8c9ea708 Passed LTC LLR: 2.94 (-2.94,2.94) <0.50,3.00> Total: 127656 W: 34505 L: 34028 D: 59123 Ptnml(0-2): 116, 12435, 38261, 12888, 128 https://tests.stockfishchess.org/tests/view/61e31db5babab931824dff5e closes https://github.com/official-stockfish/Stockfish/pull/3892 Bench: 4464962 --- src/misc.h | 3 +++ src/search.cpp | 8 +++++++- src/thread.h | 1 + 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/misc.h b/src/misc.h index 688d00e7..b9626733 100644 --- a/src/misc.h +++ b/src/misc.h @@ -105,6 +105,9 @@ class RunningAverage { bool is_greater(int64_t a, int64_t b) { return b * average > a * PERIOD * RESOLUTION ; } + int64_t value() + { return average / (PERIOD * RESOLUTION); } + private : static constexpr int64_t PERIOD = 4096; static constexpr int64_t RESOLUTION = 1024; diff --git a/src/search.cpp b/src/search.cpp index c81496d1..c9d5da64 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -329,6 +329,7 @@ void Thread::search() { doubleExtensionAverage[WHITE].set(0, 100); // initialize the running average at 0% doubleExtensionAverage[BLACK].set(0, 100); // initialize the running average at 0% + complexityAverage.set(232, 1); nodesLastExplosive = nodes; nodesLastNormal = nodes; @@ -496,7 +497,10 @@ void Thread::search() { double reduction = (1.47 + mainThread->previousTimeReduction) / (2.32 * timeReduction); double bestMoveInstability = 1.073 + std::max(1.0, 2.25 - 9.9 / rootDepth) * totBestMoveChanges / Threads.size(); - double totalTime = Time.optimum() * fallingEval * reduction * bestMoveInstability; + int complexity = mainThread->complexityAverage.value(); + double complexPosition = std::clamp(1.0 + (complexity - 232) / 1750.0, 0.5, 1.5); + + double totalTime = Time.optimum() * fallingEval * reduction * bestMoveInstability * complexPosition; // Cap used time in case of a single legal move for a better viewer experience in tournaments // yielding correct scores and sufficiently fast moves. @@ -806,6 +810,8 @@ namespace { improving = improvement > 0; complexity = abs(ss->staticEval - (us == WHITE ? eg_value(pos.psq_score()) : -eg_value(pos.psq_score()))); + thisThread->complexityAverage.update(complexity); + // Step 7. Futility pruning: child node (~25 Elo). // The depth condition is important for mate finding. if ( !ss->ttPv diff --git a/src/thread.h b/src/thread.h index a6b0b5a0..c3d38f3c 100644 --- a/src/thread.h +++ b/src/thread.h @@ -61,6 +61,7 @@ public: Material::Table materialTable; size_t pvIdx, pvLast; RunningAverage doubleExtensionAverage[COLOR_NB]; + RunningAverage complexityAverage; uint64_t nodesLastExplosive; uint64_t nodesLastNormal; std::atomic nodes, tbHits, bestMoveChanges; From 48bf1a386f031947d059a0dc26616366b0f2d5d3 Mon Sep 17 00:00:00 2001 From: ppigazzini Date: Wed, 19 Jan 2022 16:56:38 +0100 Subject: [PATCH 073/105] Add msys2 Clang x86_64 to GitHub Action matrix Also use Windows Server 2022 virtual environment for msys2 builds. closes https://github.com/official-stockfish/Stockfish/pull/3893 No functional change --- .github/workflows/stockfish.yml | 22 +++++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/.github/workflows/stockfish.yml b/.github/workflows/stockfish.yml index 54b0cb12..33126a11 100644 --- a/.github/workflows/stockfish.yml +++ b/.github/workflows/stockfish.yml @@ -61,8 +61,8 @@ jobs: shell: 'bash {0}' } - { - name: "Windows 2019 Mingw-w64 GCC x86_64", - os: windows-2019, + name: "Windows 2022 Mingw-w64 GCC x86_64", + os: windows-2022, compiler: g++, comp: gcc, run_expensive_tests: false, @@ -73,8 +73,8 @@ jobs: shell: 'msys2 {0}' } - { - name: "Windows 2019 Mingw-w64 GCC i686", - os: windows-2019, + name: "Windows 2022 Mingw-w64 GCC i686", + os: windows-2022, compiler: g++, comp: gcc, run_expensive_tests: false, @@ -84,6 +84,18 @@ jobs: msys_env: 'i686', shell: 'msys2 {0}' } + - { + name: "Windows 2022 Mingw-w64 Clang x86_64", + os: windows-2022, + compiler: clang++, + comp: clang, + run_expensive_tests: false, + run_32bit_tests: false, + run_64bit_tests: true, + msys_sys: 'clang64', + msys_env: 'clang-x86_64', + shell: 'msys2 {0}' + } defaults: run: @@ -105,7 +117,7 @@ jobs: uses: msys2/setup-msys2@v2 with: msystem: ${{matrix.config.msys_sys}} - install: mingw-w64-${{matrix.config.msys_env}}-gcc make git expect + install: mingw-w64-${{matrix.config.msys_env}}-${{matrix.config.comp}} make git expect - name: Download the used network from the fishtest framework run: | From 67062637f48e7d63e750dee63ba9e881ee6d9382 Mon Sep 17 00:00:00 2001 From: ppigazzini Date: Mon, 17 Jan 2022 14:03:16 +0100 Subject: [PATCH 074/105] Improve Makefile for Windows native builds A Windows Native Build (WNB) can be done: - on Windows, using a recent mingw-w64 g++/clang compiler distributed by msys2, cygwin and others - on Linux, using mingw-w64 g++ to cross compile Improvements: - check for a WNB in a proper way and set a variable to simplify the code - set the proper EXE for a WNB - use the proper name for the mingw-w64 clang compiler - use the static linking for a WNB - use wine to make a PGO cross compile on Linux (also with Intel SDE) - enable the LTO build for mingw-w64 g++ compiler - set `lto=auto` to use the make's job server, if available, or otherwise to fall back to autodetection of the number of CPU threads - clean up all the temporary LTO files saved in the local directory Tested on: - msys2 MINGW64 (g++), UCRT64 (g++), MINGW32 (g++), CLANG64 (clang) environments - cygwin mingw-w64 g++ - Ubuntu 18.04 & 21.10 mingw-w64 PGO cross compile (also with Intel SDE) closes #3891 No functional change --- src/Makefile | 80 +++++++++++++++++++++++++--------------------------- 1 file changed, 39 insertions(+), 41 deletions(-) diff --git a/src/Makefile b/src/Makefile index 90e596af..1b121299 100644 --- a/src/Makefile +++ b/src/Makefile @@ -19,11 +19,27 @@ ### Section 1. General Configuration ### ========================================================================== +### Establish the operating system name +KERNEL = $(shell uname -s) +ifeq ($(KERNEL),Linux) + OS = $(shell uname -o) +endif + +### Target Windows OS +ifeq ($(OS),Windows_NT) + target_windows = yes +else ifeq ($(COMP),mingw) + target_windows = yes + ifeq ($(WINE_PATH),) + WINE_PATH = $(shell which wine) + endif +endif + ### Executable name -ifeq ($(COMP),mingw) -EXE = stockfish.exe +ifeq ($(target_windows),yes) + EXE = stockfish.exe else -EXE = stockfish + EXE = stockfish endif ### Installation dir definitions @@ -32,9 +48,9 @@ BINDIR = $(PREFIX)/bin ### Built-in benchmark for pgo-builds ifeq ($(SDE_PATH),) - PGOBENCH = ./$(EXE) bench + PGOBENCH = $(WINE_PATH) ./$(EXE) bench else - PGOBENCH = $(SDE_PATH) -- ./$(EXE) bench + PGOBENCH = $(SDE_PATH) -- $(WINE_PATH) ./$(EXE) bench endif ### Source and object files @@ -47,12 +63,6 @@ OBJS = $(notdir $(SRCS:.cpp=.o)) VPATH = syzygy:nnue:nnue/features -### Establish the operating system name -KERNEL = $(shell uname -s) -ifeq ($(KERNEL),Linux) - OS = $(shell uname -o) -endif - ### ========================================================================== ### Section 2. High-level Configuration ### ========================================================================== @@ -365,6 +375,10 @@ ifeq ($(COMP),gcc) endif endif +ifeq ($(target_windows),yes) + LDFLAGS += -static +endif + ifeq ($(COMP),mingw) comp=mingw @@ -381,9 +395,7 @@ ifeq ($(COMP),mingw) CXX=i686-w64-mingw32-c++-posix endif endif - CXXFLAGS += -pedantic -Wextra -Wshadow - LDFLAGS += -static endif ifeq ($(COMP),icc) @@ -395,19 +407,19 @@ endif ifeq ($(COMP),clang) comp=clang CXX=clang++ + ifeq ($(target_windows),yes) + CXX=x86_64-w64-mingw32-clang++ + endif + CXXFLAGS += -pedantic -Wextra -Wshadow - ifneq ($(KERNEL),Darwin) - ifneq ($(KERNEL),OpenBSD) - ifneq ($(KERNEL),FreeBSD) - ifneq ($(findstring MINGW,$(KERNEL)),MINGW) + ifeq ($(filter $(KERNEL),Darwin OpenBSD FreeBSD),) + ifeq ($(target_windows),) ifneq ($(RTLIB),compiler-rt) LDFLAGS += -latomic endif endif endif - endif - endif ifeq ($(arch),$(filter $(arch),armv7 armv8)) ifeq ($(OS),Android) @@ -418,11 +430,6 @@ ifeq ($(COMP),clang) CXXFLAGS += -m$(bits) LDFLAGS += -m$(bits) endif - - ifeq ($(findstring MINGW,$(KERNEL)),MINGW) - LDFLAGS += -static - endif - endif ifeq ($(KERNEL),Darwin) @@ -656,9 +663,7 @@ ifeq ($(optimize),yes) ifeq ($(debug), no) ifeq ($(comp),clang) CXXFLAGS += -flto - ifneq ($(findstring MINGW,$(KERNEL)),) - CXXFLAGS += -fuse-ld=lld - else ifneq ($(findstring MSYS,$(KERNEL)),) + ifeq ($(target_windows),yes) CXXFLAGS += -fuse-ld=lld endif LDFLAGS += $(CXXFLAGS) @@ -669,25 +674,17 @@ ifeq ($(debug), no) ifeq ($(gccisclang),) CXXFLAGS += -flto LDFLAGS += $(CXXFLAGS) -flto=jobserver - ifneq ($(findstring MINGW,$(KERNEL)),) - LDFLAGS += -save-temps - else ifneq ($(findstring MSYS,$(KERNEL)),) - LDFLAGS += -save-temps - endif else CXXFLAGS += -flto LDFLAGS += $(CXXFLAGS) endif -# To use LTO and static linking on windows, the tool chain requires a recent gcc: -# gcc version 10.1 in msys2 or TDM-GCC version 9.2 are known to work, older might not. -# So, only enable it for a cross from Linux by default. +# To use LTO and static linking on Windows, +# the tool chain requires gcc version 10.1 or later. else ifeq ($(comp),mingw) - ifeq ($(KERNEL),Linux) ifneq ($(arch),i386) - CXXFLAGS += -flto - LDFLAGS += $(CXXFLAGS) -flto=jobserver - endif + CXXFLAGS += -flto=auto + LDFLAGS += $(CXXFLAGS) -save-temps endif endif endif @@ -843,8 +840,9 @@ profileclean: @rm -rf profdir @rm -f bench.txt *.gcda *.gcno ./syzygy/*.gcda ./nnue/*.gcda ./nnue/features/*.gcda *.s @rm -f stockfish.profdata *.profraw - @rm -f stockfish.exe.lto_wrapper_args - @rm -f stockfish.exe.ltrans.out + @rm -f stockfish.*args* + @rm -f stockfish.*lt* + @rm -f stockfish.res @rm -f ./-lstdc++.res default: From 77cf5704b6deda52171dafeb2fae370273ebd797 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Thu, 20 Jan 2022 17:49:27 +0100 Subject: [PATCH 075/105] Revert -flto=auto on mingw causes issues on some installations (glinscott/fishtest#1255). closes https://github.com/official-stockfish/Stockfish/pull/3898 No functional change --- src/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile b/src/Makefile index 1b121299..5f3e739f 100644 --- a/src/Makefile +++ b/src/Makefile @@ -683,7 +683,7 @@ ifeq ($(debug), no) # the tool chain requires gcc version 10.1 or later. else ifeq ($(comp),mingw) ifneq ($(arch),i386) - CXXFLAGS += -flto=auto + CXXFLAGS += -flto LDFLAGS += $(CXXFLAGS) -save-temps endif endif From 9083050be692b2d9a4f281e78b967755e00cfc39 Mon Sep 17 00:00:00 2001 From: "J. Oster" Date: Sat, 15 Jan 2022 18:18:52 +0100 Subject: [PATCH 076/105] Simplify limiting extensions. Replace the current method for limiting extensions to avoid search getting stuck with a much simpler method. the test position in https://github.com/official-stockfish/Stockfish/commit/73018a03375b4b72ee482eb5a4a2152d7e4f0aac can still be searched without stuck search. fixes #3815 where the search now makes progress with rootDepth shows robust behavior in a d10 search for 1M positions. passed STC https://tests.stockfishchess.org/tests/view/61e303e3babab931824dfb18 LLR: 2.94 (-2.94,2.94) <-2.25,0.25> Total: 57568 W: 15449 L: 15327 D: 26792 Ptnml(0-2): 243, 6211, 15779, 6283, 268 passed LTC https://tests.stockfishchess.org/tests/view/61e3586cbabab931824e091c LLR: 2.96 (-2.94,2.94) <-2.25,0.25> Total: 128200 W: 34632 L: 34613 D: 58955 Ptnml(0-2): 124, 12559, 38710, 12588, 119 closes https://github.com/official-stockfish/Stockfish/pull/3899 Bench: 4550528 --- src/search.cpp | 152 +++++++++++++++++++------------------------------ src/thread.h | 7 +-- 2 files changed, 59 insertions(+), 100 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index c9d5da64..792c9729 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -88,30 +88,6 @@ namespace { return VALUE_DRAW + Value(2 * (thisThread->nodes & 1) - 1); } - // Check if the current thread is in a search explosion - ExplosionState search_explosion(Thread* thisThread) { - - uint64_t nodesNow = thisThread->nodes; - bool explosive = thisThread->doubleExtensionAverage[WHITE].is_greater(2, 100) - || thisThread->doubleExtensionAverage[BLACK].is_greater(2, 100); - - if (explosive) - thisThread->nodesLastExplosive = nodesNow; - else - thisThread->nodesLastNormal = nodesNow; - - if ( explosive - && thisThread->state == EXPLOSION_NONE - && nodesNow - thisThread->nodesLastNormal > 6000000) - thisThread->state = MUST_CALM_DOWN; - - if ( thisThread->state == MUST_CALM_DOWN - && nodesNow - thisThread->nodesLastExplosive > 6000000) - thisThread->state = EXPLOSION_NONE; - - return thisThread->state; - } - // Skill structure is used to implement strength limit. If we have an uci_elo then // we convert it to a suitable fractional skill level using anchoring to CCRL Elo // (goldfish 1.13 = 2000) and a fit through Ordo derived Elo for match (TC 60+0.6) @@ -327,16 +303,11 @@ void Thread::search() { multiPV = std::min(multiPV, rootMoves.size()); - doubleExtensionAverage[WHITE].set(0, 100); // initialize the running average at 0% - doubleExtensionAverage[BLACK].set(0, 100); // initialize the running average at 0% complexityAverage.set(232, 1); - nodesLastExplosive = nodes; - nodesLastNormal = nodes; - state = EXPLOSION_NONE; - trend = SCORE_ZERO; - optimism[ us] = Value(25); - optimism[~us] = -optimism[us]; + trend = SCORE_ZERO; + optimism[ us] = Value(25); + optimism[~us] = -optimism[us]; int searchAgainCounter = 0; @@ -548,14 +519,6 @@ namespace { template Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, bool cutNode) { - Thread* thisThread = pos.this_thread(); - - // Step 0. Limit search explosion - if ( ss->ply > 10 - && search_explosion(thisThread) == MUST_CALM_DOWN - && depth > (ss-1)->depth) - depth = (ss-1)->depth; - constexpr bool PvNode = nodeType != NonPV; constexpr bool rootNode = nodeType == Root; const Depth maxNextDepth = rootNode ? depth : depth + 1; @@ -596,6 +559,7 @@ namespace { int moveCount, captureCount, quietCount, bestMoveCount, improvement, complexity; // Step 1. Initialize node + Thread* thisThread = pos.this_thread(); ss->inCheck = pos.checkers(); priorCapture = pos.captured_piece(); Color us = pos.side_to_move(); @@ -643,9 +607,6 @@ namespace { ss->depth = depth; Square prevSq = to_sq((ss-1)->currentMove); - // Update the running average statistics for double extensions - thisThread->doubleExtensionAverage[us].update(ss->depth > (ss-1)->depth); - // Initialize statScore to zero for the grandchildren of the current position. // So statScore is shared between all grandchildren and only the first grandchild // starts with statScore = 0. Later grandchildren start with the last calculated @@ -1077,65 +1038,68 @@ moves_loop: // When in check, search starts here } // Step 14. Extensions (~66 Elo) - - // Singular extension search (~58 Elo). If all moves but one fail low on a - // search of (alpha-s, beta-s), and just one fails high on (alpha, beta), - // then that move is singular and should be extended. To verify this we do - // a reduced search on all the other moves but the ttMove and if the - // result is lower than ttValue minus a margin, then we will extend the ttMove. - if ( !rootNode - && depth >= 6 + 2 * (PvNode && tte->is_pv()) - && move == ttMove - && !excludedMove // Avoid recursive singular search - /* && ttValue != VALUE_NONE Already implicit in the next condition */ - && abs(ttValue) < VALUE_KNOWN_WIN - && (tte->bound() & BOUND_LOWER) - && tte->depth() >= depth - 3) + // We take care to not overdo to avoid search getting stuck. + if (ss->ply < thisThread->rootDepth * 2) { - Value singularBeta = ttValue - 3 * depth; - Depth singularDepth = (depth - 1) / 2; - - ss->excludedMove = move; - value = search(pos, ss, singularBeta - 1, singularBeta, singularDepth, cutNode); - ss->excludedMove = MOVE_NONE; - - if (value < singularBeta) + // Singular extension search (~58 Elo). If all moves but one fail low on a + // search of (alpha-s, beta-s), and just one fails high on (alpha, beta), + // then that move is singular and should be extended. To verify this we do + // a reduced search on all the other moves but the ttMove and if the + // result is lower than ttValue minus a margin, then we will extend the ttMove. + if ( !rootNode + && depth >= 6 + 2 * (PvNode && tte->is_pv()) + && move == ttMove + && !excludedMove // Avoid recursive singular search + /* && ttValue != VALUE_NONE Already implicit in the next condition */ + && abs(ttValue) < VALUE_KNOWN_WIN + && (tte->bound() & BOUND_LOWER) + && tte->depth() >= depth - 3) { - extension = 1; + Value singularBeta = ttValue - 3 * depth; + Depth singularDepth = (depth - 1) / 2; - // Avoid search explosion by limiting the number of double extensions - if ( !PvNode - && value < singularBeta - 75 - && ss->doubleExtensions <= 6) - extension = 2; + ss->excludedMove = move; + value = search(pos, ss, singularBeta - 1, singularBeta, singularDepth, cutNode); + ss->excludedMove = MOVE_NONE; + + if (value < singularBeta) + { + extension = 1; + + // Avoid search explosion by limiting the number of double extensions + if ( !PvNode + && value < singularBeta - 75 + && ss->doubleExtensions <= 6) + extension = 2; + } + + // Multi-cut pruning + // Our ttMove is assumed to fail high, and now we failed high also on a reduced + // search without the ttMove. So we assume this expected Cut-node is not singular, + // that multiple moves fail high, and we can prune the whole subtree by returning + // a soft bound. + else if (singularBeta >= beta) + return singularBeta; + + // If the eval of ttMove is greater than beta, we reduce it (negative extension) + else if (ttValue >= beta) + extension = -2; } - // Multi-cut pruning - // Our ttMove is assumed to fail high, and now we failed high also on a reduced - // search without the ttMove. So we assume this expected Cut-node is not singular, - // that multiple moves fail high, and we can prune the whole subtree by returning - // a soft bound. - else if (singularBeta >= beta) - return singularBeta; + // Check extensions (~1 Elo) + else if ( givesCheck + && depth > 6 + && abs(ss->staticEval) > 100) + extension = 1; - // If the eval of ttMove is greater than beta, we reduce it (negative extension) - else if (ttValue >= beta) - extension = -2; + // Quiet ttMove extensions (~0 Elo) + else if ( PvNode + && move == ttMove + && move == ss->killers[0] + && (*contHist[0])[movedPiece][to_sq(move)] >= 10000) + extension = 1; } - // Check extensions (~1 Elo) - else if ( givesCheck - && depth > 6 - && abs(ss->staticEval) > 100) - extension = 1; - - // Quiet ttMove extensions (~0 Elo) - else if ( PvNode - && move == ttMove - && move == ss->killers[0] - && (*contHist[0])[movedPiece][to_sq(move)] >= 10000) - extension = 1; - // Add extension to new depth newDepth += extension; ss->doubleExtensions = (ss-1)->doubleExtensions + (extension == 2); diff --git a/src/thread.h b/src/thread.h index c3d38f3c..594a8ea2 100644 --- a/src/thread.h +++ b/src/thread.h @@ -60,16 +60,11 @@ public: Pawns::Table pawnsTable; Material::Table materialTable; size_t pvIdx, pvLast; - RunningAverage doubleExtensionAverage[COLOR_NB]; RunningAverage complexityAverage; - uint64_t nodesLastExplosive; - uint64_t nodesLastNormal; std::atomic nodes, tbHits, bestMoveChanges; - Value bestValue; int selDepth, nmpMinPly; Color nmpColor; - ExplosionState state; - Value optimism[COLOR_NB]; + Value bestValue, optimism[COLOR_NB]; Position rootPos; StateInfo rootState; From bddd38c45e1f1457e1435cd066036e98f54d7397 Mon Sep 17 00:00:00 2001 From: pschneider1968 <36973164+pschneider1968@users.noreply.github.com> Date: Fri, 21 Jan 2022 14:11:53 +0100 Subject: [PATCH 077/105] Fix Makefile for Android NDK cross-compile For cross-compiling to Android on windows, the Makefile needs some tweaks. Tested with Android NDK 23.1.7779620 and 21.4.7075529, using Windows 10 with clean MSYS2 environment (i.e. no MINGW/GCC/Clang toolchain in PATH) and Fedora 35, with build target: build ARCH=armv8 COMP=ndk The resulting binary runs fine inside Droidfish on my Samsung Galaxy Note20 Ultra and Samsung Galaxy Tab S7+ Other builds tested to exclude regressions: MINGW64/Clang64 build on Windows; MINGW64 cross build, native Clang and GCC builds on Fedora. wiki docs https://github.com/glinscott/fishtest/wiki/Cross-compiling-Stockfish-for-Android-on-Windows-and-Linux closes https://github.com/official-stockfish/Stockfish/pull/3901 No functional change --- src/Makefile | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/src/Makefile b/src/Makefile index 5f3e739f..9666f138 100644 --- a/src/Makefile +++ b/src/Makefile @@ -27,7 +27,9 @@ endif ### Target Windows OS ifeq ($(OS),Windows_NT) - target_windows = yes + ifneq ($(COMP),ndk) + target_windows = yes + endif else ifeq ($(COMP),mingw) target_windows = yes ifeq ($(WINE_PATH),) @@ -451,11 +453,19 @@ ifeq ($(COMP),ndk) ifeq ($(arch),armv7) CXX=armv7a-linux-androideabi16-clang++ CXXFLAGS += -mthumb -march=armv7-a -mfloat-abi=softfp -mfpu=neon - STRIP=arm-linux-androideabi-strip + ifneq ($(shell which arm-linux-androideabi-strip 2>/dev/null),) + STRIP=arm-linux-androideabi-strip + else + STRIP=llvm-strip + endif endif ifeq ($(arch),armv8) CXX=aarch64-linux-android21-clang++ - STRIP=aarch64-linux-android-strip + ifneq ($(shell which aarch64-linux-android-strip 2>/dev/null),) + STRIP=aarch64-linux-android-strip + else + STRIP=llvm-strip + endif endif LDFLAGS += -static-libstdc++ -pie -lm -latomic endif @@ -801,7 +811,7 @@ strip: install: -mkdir -p -m 755 $(BINDIR) -cp $(EXE) $(BINDIR) - -strip $(BINDIR)/$(EXE) + $(STRIP) $(BINDIR)/$(EXE) # clean all clean: objclean profileclean @@ -833,7 +843,7 @@ net: # clean binaries and objects objclean: - @rm -f $(EXE) *.o ./syzygy/*.o ./nnue/*.o ./nnue/features/*.o + @rm -f stockfish stockfish.exe *.o ./syzygy/*.o ./nnue/*.o ./nnue/features/*.o # clean auxiliary profiling files profileclean: From 8b4afcf8f7a38ee3060f39d563aad5956fe723d7 Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Tue, 25 Jan 2022 02:22:03 +0300 Subject: [PATCH 078/105] Scale child node futility pruning with previous move history. Idea is to do more futility pruning if previous move has bad histories and less if it has good histories. passed STC https://tests.stockfishchess.org/tests/view/61e3757fbabab931824e0db7 LLR: 2.96 (-2.94,2.94) <0.00,2.50> Total: 156816 W: 42282 L: 41777 D: 72757 Ptnml(0-2): 737, 17775, 40913, 18212, 771 passed LTC https://tests.stockfishchess.org/tests/view/61e43496928632f7813a5535 LLR: 2.95 (-2.94,2.94) <0.50,3.00> Total: 349968 W: 94612 L: 93604 D: 161752 Ptnml(0-2): 300, 35934, 101550, 36858, 342 closes https://github.com/official-stockfish/Stockfish/pull/3903 bench 4720954 --- src/search.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 792c9729..c3360ad1 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -777,7 +777,8 @@ namespace { // The depth condition is important for mate finding. if ( !ss->ttPv && depth < 9 - && eval - futility_margin(depth, improving) >= beta + && eval - futility_margin(depth, improving) - (ss-1)->statScore / 256 >= beta + && eval >= beta && eval < 15000) // 50% larger than VALUE_KNOWN_WIN, but smaller than TB wins. return eval; From 90d051952f4fce415f09f316e24e1701aafa7a92 Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Sat, 29 Jan 2022 06:39:40 +0300 Subject: [PATCH 079/105] Do stats updates after LMR for captures Since captures that are in LMR use continuation histories of corresponding quiet moves it makes sense to update this histories if this capture passes LMR by analogy to existing logic for quiet moves. Passed STC https://tests.stockfishchess.org/tests/view/61f367eef7fba9f1a4f1318b LLR: 2.94 (-2.94,2.94) <0.00,2.50> Total: 208464 W: 56006 L: 55407 D: 97051 Ptnml(0-2): 964, 23588, 54655, 23935, 1090 Passed LTC https://tests.stockfishchess.org/tests/view/61f41e34f7fba9f1a4f15241 LLR: 2.96 (-2.94,2.94) <0.50,3.00> Total: 69144 W: 18793 L: 18441 D: 31910 Ptnml(0-2): 65, 6982, 20142, 7302, 81 closes https://github.com/official-stockfish/Stockfish/pull/3910 bench 4637392 --- src/search.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index c3360ad1..8d5ad979 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1194,11 +1194,14 @@ moves_loop: // When in check, search starts here value = -search(pos, ss+1, -(alpha+1), -alpha, newDepth + doDeeperSearch, !cutNode); // If the move passed LMR update its stats - if (didLMR && !captureOrPromotion) + if (didLMR) { int bonus = value > alpha ? stat_bonus(newDepth) : -stat_bonus(newDepth); + if (captureOrPromotion) + bonus /= 4; + update_continuation_histories(ss, movedPiece, to_sq(move), bonus); } } From 50200de5af09db3a9143082e4e66baef11b4be2a Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Mon, 31 Jan 2022 07:25:10 +0300 Subject: [PATCH 080/105] Cleanup and update CPU contributors closes https://github.com/official-stockfish/Stockfish/pull/3917 No functional change --- Top CPU Contributors.txt | 113 ++++++++++++++++++++------------------- src/types.h | 5 -- 2 files changed, 59 insertions(+), 59 deletions(-) diff --git a/Top CPU Contributors.txt b/Top CPU Contributors.txt index 718d7cca..4bc96cde 100644 --- a/Top CPU Contributors.txt +++ b/Top CPU Contributors.txt @@ -1,90 +1,91 @@ -Contributors to Fishtest with >10,000 CPU hours, as of 2022-01-08. +Contributors to Fishtest with >10,000 CPU hours, as of 2022-02-05. Thank you! Username CPU Hours Games played ------------------------------------------------------------------ -noobpwnftw 30323785 2111752181 -mlang 2597136 178003354 -dew 1598255 95747056 -technologov 1395130 59347018 -grandphish2 1028906 63396841 +noobpwnftw 30730952 2158431735 +mlang 2729669 187335452 +technologov 1696847 74478658 +dew 1635640 97483012 +grandphish2 1062754 64955639 tvijlbrief 795993 51894442 -TueRens 737922 46359276 -okrout 719183 57150314 +okrout 773704 63465204 +TueRens 766198 47770388 mibere 703840 46867607 -JojoM 689134 42001146 -linrock 594355 16779359 -pemo 575248 28386103 -gvreuls 509219 33205908 -cw 500695 33575803 -fastgm 479238 28830588 +JojoM 703005 42689868 +pemo 634102 29868807 +linrock 626939 17408017 +gvreuls 517442 33605006 +cw 503905 33850487 +fastgm 482847 29004732 crunchy 427035 27344275 -CSU_Dynasty 410969 27877556 -ctoks 393901 26299629 -oz 354661 26331020 +CSU_Dynasty 415864 28116776 +ctoks 403102 26737127 +oz 357710 26490208 +bcross 331095 23165889 Fisherman 327231 21829379 -bcross 325119 22871639 -velislav 320581 20663382 -leszek 291605 18475167 -Dantist 239411 15236750 -mgrabiak 229336 15004308 +velislav 321708 20729264 +leszek 303654 19063973 +Dantist 251015 15843226 +mgrabiak 231973 15162494 glinscott 217799 13780820 -robal 211837 13563250 +robal 213960 13665726 nordlandia 211692 13484886 -drabel 200377 13730626 +drabel 200914 13755384 bking_US 198894 11876016 +mhoram 180229 11610075 Thanar 179852 12365359 -vdv 175535 9904264 -mhoram 173134 11257113 +vdv 175544 9904472 spams 157128 10319326 marrco 150300 9402229 sqrt2 147963 9724586 -vdbergh 137425 8954767 +vdbergh 137429 8955089 CoffeeOne 137100 5024116 malala 136182 8002293 xoto 133759 9159372 -davar 122113 7961971 +rpngn 131285 8657757 +davar 122661 7996937 dsmith 122059 7570238 amicic 119659 7937885 -rpngn 118952 8100045 Data 113305 8220352 BrunoBanani 112960 7436849 CypressChess 108321 7759588 MaZePallas 102823 6633619 sterni1971 100532 5880772 sunu 100167 7040199 +DesolatedDodo 99038 6414626 ElbertoOne 99028 7023771 skiminki 98123 6478402 -DesolatedDodo 93686 6139198 brabos 92118 6186135 -cuistot 90357 5350988 +cuistot 90358 5351004 psk 89957 5984901 racerschmacer 85712 6119648 Vizvezdenec 83761 5344740 +sschnee 83003 4840890 0x3C33 82614 5271253 BRAVONE 81239 5054681 -sschnee 78091 4678078 nssy 76497 5259388 teddybaer 75125 5407666 Pking_cda 73776 5293873 +zeryl 73335 4774257 jromang 72192 5057715 solarlight 70517 5028306 dv8silencer 70287 3883992 Bobo1239 68515 4652287 -zeryl 68203 4516139 manap 66273 4121774 tinker 64333 4268790 -yurikvelo 61692 4262042 +yurikvelo 63371 4335060 qurashee 61208 3429862 robnjr 57262 4053117 +Wolfgang 57014 3561352 Freja 56938 3733019 ttruscott 56010 3680085 rkl 55132 4164467 -Wolfgang 54087 3415872 renouve 53811 3501516 finfish 51360 3370515 eva42 51272 3599691 -eastorwest 51055 3451203 +Calis007 51182 3131552 +eastorwest 51058 3451555 rap 49985 3219146 pb00067 49727 3298270 Spprtr 48260 3141959 @@ -92,11 +93,11 @@ bigpen0r 47667 3336927 ronaldjerum 47654 3240695 MaxKlaxxMiner 47584 2972142 biffhero 46564 3111352 +megaman7de 45992 2952006 Fifis 45843 3088497 VoyagerOne 45476 3452465 speedycpu 43842 3003273 jbwiebe 43305 2805433 -megaman7de 43042 2823256 Antihistamine 41788 2761312 mhunt 41735 2691355 homyur 39893 2850481 @@ -109,18 +110,17 @@ jmdana 36157 2210661 strelock 34716 2074055 EthanOConnor 33370 2090311 slakovv 32915 2021889 -Calis007 32024 2163604 +armo9494 32129 2551682 +tolkki963 32114 1932256 manapbk 30987 1810399 DMBK 30675 2383552 Prcuvu 30377 2170122 anst 30301 2190091 -armo9494 30198 2438202 jkiiski 30136 1904470 -tolkki963 29918 1822290 +gopeto 29886 1979118 hyperbolic.tom 29840 2017394 chuckstablers 29659 2093438 Pyafue 29650 1902349 -gopeto 28881 1896862 OuaisBla 27636 1578800 chriswk 26902 1868317 achambord 26582 1767323 @@ -132,11 +132,12 @@ Sharaf_DG 24765 1786697 ncfish1 24411 1520927 rodneyc 24275 1410450 agg177 23890 1395014 +belzedar94 23707 1593860 JanErik 23408 1703875 Isidor 23388 1680691 Norabor 23339 1602636 +Ente 23093 1642458 cisco2015 22897 1762669 -Ente 22810 1628234 Zirie 22542 1472937 team-oh 22272 1636708 MazeOfGalious 21978 1629593 @@ -148,12 +149,12 @@ nesoneg 21494 1463031 sphinx 21211 1384728 jjoshua2 21001 1423089 horst.prack 20878 1465656 +user213718 20783 1379584 0xB00B1ES 20590 1208666 j3corre 20405 941444 Adrian.Schmidt123 20316 1281436 wei 19973 1745989 -belzedar94 19818 1434252 -user213718 19608 1334650 +Roady 19848 1335928 rstoesser 19569 1293588 eudhan 19274 1283717 vulcan 18871 1729392 @@ -163,24 +164,24 @@ ville 17883 1384026 chris 17698 1487385 purplefishies 17595 1092533 dju 17353 978595 +kdave 17183 1242754 DragonLord 17014 1162790 +thirdlife 16996 447356 +spcc 16932 1130940 +fishtester 16644 1123000 +Ulysses 16490 1184400 IgorLeMasson 16064 1147232 -Roady 15677 1121476 ako027ako 15671 1173203 -kdave 15539 1160356 Nikolay.IT 15154 1068349 Andrew Grant 15114 895539 OssumOpossum 14857 1007129 -spcc 14838 1034050 Karby 14808 867120 +AndreasKrug 14608 1152093 enedene 14476 905279 -fishtester 14411 1016252 jsys14 14340 844792 bpfliegel 14298 884523 -AndreasKrug 14096 1126301 mpx86 14019 759568 jpulman 13982 870599 -Ulysses 13977 1073410 crocogoat 13803 1117422 joster 13794 950160 Nesa92 13786 1114691 @@ -188,12 +189,13 @@ mbeier 13650 1044928 Hjax 13535 915487 Dark_wizzie 13422 1007152 Rudolphous 13244 883140 +MarcusTullius 13221 843169 Machariel 13010 863104 mabichito 12903 749391 thijsk 12886 722107 AdrianSA 12860 804972 +infinigon 12807 937332 Flopzee 12698 894821 -infinigon 12638 933684 fatmurphy 12547 853210 scuzzi 12511 845761 SapphireBrand 12416 969604 @@ -202,19 +204,21 @@ Farseer 12249 694108 pgontarz 12151 848794 stocky 11954 699440 mschmidt 11941 803401 +dbernier 11609 818636 Maxim 11543 836024 +pirt 11516 894513 infinity 11470 727027 -pirt 11434 889369 aga 11409 695071 torbjo 11395 729145 Thomas A. Anderson 11372 732094 savage84 11358 670860 -FormazChar 11304 847663 -dbernier 11274 806566 +markkulix 11331 739098 +FormazChar 11308 847735 d64 11263 789184 MooTheCow 11237 720174 snicolet 11106 869170 ali-al-zhrani 11098 768494 +whelanh 11067 235676 basepi 10637 744851 Cubox 10621 826448 michaelrpg 10509 739239 @@ -223,3 +227,4 @@ dzjp 10343 732529 Garruk 10332 703905 ols 10259 570669 lbraesch 10252 647825 +Jackfish 10098 682338 diff --git a/src/types.h b/src/types.h index a3a873fa..cf42bc9f 100644 --- a/src/types.h +++ b/src/types.h @@ -173,11 +173,6 @@ enum Bound { BOUND_EXACT = BOUND_UPPER | BOUND_LOWER }; -enum ExplosionState { - EXPLOSION_NONE, - MUST_CALM_DOWN -}; - enum Value : int { VALUE_ZERO = 0, VALUE_DRAW = 0, From e178a09c47e340e5183d9bd2d331741aa837ba8a Mon Sep 17 00:00:00 2001 From: ppigazzini Date: Mon, 31 Jan 2022 14:37:45 +0100 Subject: [PATCH 081/105] Drop sse from target "x86-32" have maximal compatibility on legacy target arch, now supporting AMD Athlon The old behavior can anyway be selected by the user if needed, for example make -j profile-build ARCH=x86-32 sse=yes fixes #3904 closes https://github.com/official-stockfish/Stockfish/pull/3918 No functional change --- src/Makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/Makefile b/src/Makefile index 9666f138..eff8baca 100644 --- a/src/Makefile +++ b/src/Makefile @@ -152,7 +152,7 @@ ifeq ($(findstring x86,$(ARCH)),x86) ifeq ($(findstring x86-32,$(ARCH)),x86-32) arch = i386 bits = 32 - sse = yes + sse = no mmx = yes else arch = x86_64 From 95d7369e54f20715345cf5408040f3c7d1ec8415 Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Fri, 4 Feb 2022 22:42:41 +0300 Subject: [PATCH 082/105] Introduce movecount pruning for quiet check evasions in qsearch Idea of this patch is that we usually don't consider quiet check evasions as "good" ones and prefer capture based ones instead. So it makes sense to think that if in qsearch 2 quiet check evasions failed to produce anything good 3rd and further ones wouldn't be good either. passed STC https://tests.stockfishchess.org/tests/view/61fc1b1ed508ec6a1c9f397c LLR: 2.94 (-2.94,2.94) <0.00,2.50> Total: 58800 W: 15947 L: 15626 D: 27227 Ptnml(0-2): 273, 6568, 15462, 6759, 338 passed LTC https://tests.stockfishchess.org/tests/view/61fcc56dd508ec6a1c9f5619 LLR: 2.95 (-2.94,2.94) <0.50,3.00> Total: 89544 W: 24208 L: 23810 D: 41526 Ptnml(0-2): 81, 9038, 26134, 9440, 79 closes https://github.com/official-stockfish/Stockfish/pull/3920 bench 4830082 --- src/search.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/search.cpp b/src/search.cpp index 8d5ad979..c0f77f8a 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1479,6 +1479,8 @@ moves_loop: // When in check, search starts here contHist, prevSq); + int quietCheckEvasions = 0; + // Loop through the moves until no moves remain or a beta cutoff occurs while ((move = mp.next_move()) != MOVE_NONE) { @@ -1540,6 +1542,15 @@ moves_loop: // When in check, search starts here && (*contHist[1])[pos.moved_piece(move)][to_sq(move)] < CounterMovePruneThreshold) continue; + // movecount pruning for quiet check evasions + if ( bestValue > VALUE_TB_LOSS_IN_MAX_PLY + && quietCheckEvasions > 1 + && !captureOrPromotion + && ss->inCheck) + continue; + + quietCheckEvasions += !captureOrPromotion && ss->inCheck; + // Make and search the move pos.do_move(move, st, givesCheck); value = -qsearch(pos, ss+1, -beta, -alpha, depth - 1); From 4d3950c6eb80c932af00f6495668d5c5adf3701b Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Sat, 5 Feb 2022 04:03:02 +0300 Subject: [PATCH 083/105] Reintroduce razoring Razoring was simplified away some years ago, this patch reintroduces it in a slightly different form. Now for low depths if eval is far below alpha we check if qsearch can push it above alpha - and if it can't we return a fail low. passed STC https://tests.stockfishchess.org/tests/view/61fbf968d508ec6a1c9f3274 LLR: 2.94 (-2.94,2.94) <0.00,2.50> Total: 226120 W: 61106 L: 60472 D: 104542 Ptnml(0-2): 1118, 25592, 59080, 26078, 1192 passed LTC https://tests.stockfishchess.org/tests/view/61fcc569d508ec6a1c9f5617 LLR: 2.94 (-2.94,2.94) <0.50,3.00> Total: 113128 W: 30851 L: 30397 D: 51880 Ptnml(0-2): 114, 11483, 32926, 11917, 124 closes https://github.com/official-stockfish/Stockfish/pull/3921 bench 4684080 --- src/search.cpp | 38 ++++++++++++++++++++++++-------------- 1 file changed, 24 insertions(+), 14 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index c0f77f8a..6ca3b56e 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -773,7 +773,17 @@ namespace { thisThread->complexityAverage.update(complexity); - // Step 7. Futility pruning: child node (~25 Elo). + // Step 7. Razoring. + // If eval is really low check with qsearch if it can exceed alpha, if it can't, + // return a fail low. + if (!PvNode && depth <= 6 && eval < alpha - 400 - 300 * depth * depth) + { + value = qsearch(pos, ss, alpha - 1, alpha); + if (value < alpha) + return value; + } + + // Step 8. Futility pruning: child node (~25 Elo). // The depth condition is important for mate finding. if ( !ss->ttPv && depth < 9 @@ -782,7 +792,7 @@ namespace { && eval < 15000) // 50% larger than VALUE_KNOWN_WIN, but smaller than TB wins. return eval; - // Step 8. Null move search with verification search (~22 Elo) + // Step 9. Null move search with verification search (~22 Elo) if ( !PvNode && (ss-1)->currentMove != MOVE_NULL && (ss-1)->statScore < 23767 @@ -834,7 +844,7 @@ namespace { probCutBeta = beta + 209 - 44 * improving; - // Step 9. ProbCut (~4 Elo) + // Step 10. ProbCut (~4 Elo) // If we have a good enough capture and a reduced search returns a value // much above beta, we can (almost) safely prune the previous move. if ( !PvNode @@ -895,7 +905,7 @@ namespace { ss->ttPv = ttPv; } - // Step 10. If the position is not in TT, decrease depth by 2 or 1 depending on node type (~3 Elo) + // Step 11. If the position is not in TT, decrease depth by 2 or 1 depending on node type (~3 Elo) if ( PvNode && depth >= 6 && !ttMove) @@ -908,7 +918,7 @@ namespace { moves_loop: // When in check, search starts here - // Step 11. A small Probcut idea, when we are in check (~0 Elo) + // Step 12. A small Probcut idea, when we are in check (~0 Elo) probCutBeta = beta + 409; if ( ss->inCheck && !PvNode @@ -945,7 +955,7 @@ moves_loop: // When in check, search starts here && (tte->bound() & BOUND_UPPER) && tte->depth() >= depth; - // Step 12. Loop through all pseudo-legal moves until no moves remain + // Step 13. Loop through all pseudo-legal moves until no moves remain // or a beta cutoff occurs. while ((move = mp.next_move(moveCountPruning)) != MOVE_NONE) { @@ -985,7 +995,7 @@ moves_loop: // When in check, search starts here Value delta = beta - alpha; - // Step 13. Pruning at shallow depth (~98 Elo). Depth conditions are important for mate finding. + // Step 14. Pruning at shallow depth (~98 Elo). Depth conditions are important for mate finding. if ( !rootNode && pos.non_pawn_material(us) && bestValue > VALUE_TB_LOSS_IN_MAX_PLY) @@ -1038,7 +1048,7 @@ moves_loop: // When in check, search starts here } } - // Step 14. Extensions (~66 Elo) + // Step 15. Extensions (~66 Elo) // We take care to not overdo to avoid search getting stuck. if (ss->ply < thisThread->rootDepth * 2) { @@ -1115,12 +1125,12 @@ moves_loop: // When in check, search starts here [movedPiece] [to_sq(move)]; - // Step 15. Make the move + // Step 16. Make the move pos.do_move(move, st, givesCheck); bool doDeeperSearch = false; - // Step 16. Late moves reduction / extension (LMR, ~98 Elo) + // Step 17. Late moves reduction / extension (LMR, ~98 Elo) // We use various heuristics for the sons of a node after the first son has // been searched. In general we would like to reduce them, but there are many // cases where we extend a son if it has good chances to be "interesting". @@ -1188,7 +1198,7 @@ moves_loop: // When in check, search starts here didLMR = false; } - // Step 17. Full depth search when LMR is skipped or fails high + // Step 18. Full depth search when LMR is skipped or fails high if (doFullDepthSearch) { value = -search(pos, ss+1, -(alpha+1), -alpha, newDepth + doDeeperSearch, !cutNode); @@ -1218,12 +1228,12 @@ moves_loop: // When in check, search starts here std::min(maxNextDepth, newDepth), false); } - // Step 18. Undo move + // Step 19. Undo move pos.undo_move(move); assert(value > -VALUE_INFINITE && value < VALUE_INFINITE); - // Step 19. Check for a new best move + // Step 20. Check for a new best move // Finished searching the move. If a stop occurred, the return value of // the search cannot be trusted, and we return immediately without // updating best move, PV and TT. @@ -1306,7 +1316,7 @@ moves_loop: // When in check, search starts here return VALUE_DRAW; */ - // Step 20. Check for mate and stalemate + // Step 21. Check for mate and stalemate // All legal moves have been searched and if there are no legal moves, it // must be a mate or a stalemate. If we are in a singular extension search then // return a fail low score. From 08ac4e9db5d763edb788f3b01ea5c3bac494defa Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Mon, 7 Feb 2022 13:32:21 +0300 Subject: [PATCH 084/105] Do less depth reduction in null move pruning for complex positions This patch makes us reduce less depth in null move pruning if complexity is high enough. Thus, null move pruning now depends in two distinct ways on complexity, while being the only search heuristic that exploits complexity so far. passed STC https://tests.stockfishchess.org/tests/view/61fde60fd508ec6a1c9f7754 LLR: 2.94 (-2.94,2.94) <0.00,2.50> Total: 170000 W: 45555 L: 45027 D: 79418 Ptnml(0-2): 760, 19352, 44359, 19658, 871 passed LTC https://tests.stockfishchess.org/tests/view/61fe91febf46cb834cbd5c90 LLR: 2.96 (-2.94,2.94) <0.50,3.00> Total: 145272 W: 39182 L: 38651 D: 67439 Ptnml(0-2): 127, 14864, 42157, 15327, 161 closes https://github.com/official-stockfish/Stockfish/pull/3923 bench 4461945 --- src/search.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 6ca3b56e..426f7937 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -776,7 +776,9 @@ namespace { // Step 7. Razoring. // If eval is really low check with qsearch if it can exceed alpha, if it can't, // return a fail low. - if (!PvNode && depth <= 6 && eval < alpha - 400 - 300 * depth * depth) + if ( !PvNode + && depth <= 6 + && eval < alpha - 400 - 300 * depth * depth) { value = qsearch(pos, ss, alpha - 1, alpha); if (value < alpha) @@ -805,8 +807,8 @@ namespace { { assert(eval - beta >= 0); - // Null move dynamic reduction based on depth and value - Depth R = std::min(int(eval - beta) / 205, 3) + depth / 3 + 4; + // Null move dynamic reduction based on depth, eval and complexity of position + Depth R = std::min(int(eval - beta) / 205, 3) + depth / 3 + 4 - (complexity > 500); ss->currentMove = MOVE_NULL; ss->continuationHistory = &thisThread->continuationHistory[0][0][NO_PIECE][0]; From b0b31558a236301aa8578030a8a3109856634fa9 Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Wed, 9 Feb 2022 17:39:21 +0300 Subject: [PATCH 085/105] Big search tuning Most credits for this patch should go to @candirufish. Based on his big search tuning (1M games at 20+0.1s) https://tests.stockfishchess.org/tests/view/61fc7a6ed508ec6a1c9f4b7d with some hand polishing on top of it, which includes : a) correcting trend sigmoid - for some reason original tuning resulted in it being negative. This heuristic was proven to be worth some elo for years so reversing it sign is probably some random artefact; b) remove changes to continuation history based pruning - this heuristic historically was really good at providing green STCs and then failing at LTC miserably if we tried to make it more strict, original tuning was done at short time control and thus it became more strict - which doesn't scale to longer time controls; c) remove changes to improvement - not really indended :). passed STC https://tests.stockfishchess.org/tests/view/6203526e88ae2c84271c2ee2 LLR: 2.94 (-2.94,2.94) <0.00,2.50> Total: 16840 W: 4604 L: 4363 D: 7873 Ptnml(0-2): 82, 1780, 4449, 2033, 76 passed LTC https://tests.stockfishchess.org/tests/view/620376e888ae2c84271c35d4 LLR: 2.96 (-2.94,2.94) <0.50,3.00> Total: 17232 W: 4771 L: 4542 D: 7919 Ptnml(0-2): 14, 1655, 5048, 1886, 13 closes https://github.com/official-stockfish/Stockfish/pull/3926 bench 5030992 --- src/search.cpp | 93 +++++++++++++++++++++++++------------------------- 1 file changed, 46 insertions(+), 47 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 426f7937..5bc9de7b 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -63,7 +63,7 @@ namespace { // Futility margin Value futility_margin(Depth d, bool improving) { - return Value(214 * (d - improving)); + return Value(171 * (d - improving)); } // Reductions lookup table, initialized at startup @@ -71,7 +71,7 @@ namespace { Depth reduction(bool i, Depth d, int mn, Value delta, Value rootDelta) { int r = Reductions[d] * Reductions[mn]; - return (r + 1358 - int(delta) * 1024 / int(rootDelta)) / 1024 + (!i && r > 904); + return (r + 1575 - int(delta) * 1024 / int(rootDelta)) / 1024 + (!i && r > 1011); } constexpr int futility_move_count(bool improving, Depth depth) { @@ -80,7 +80,7 @@ namespace { // History and stats update bonus, based on depth int stat_bonus(Depth d) { - return std::min((6 * d + 229) * d - 215 , 2000); + return std::min((7 * d + 254) * d - 206 , 1990); } // Add a small random component to draw evaluations to avoid 3-fold blindness @@ -157,7 +157,7 @@ namespace { void Search::init() { for (int i = 1; i < MAX_MOVES; ++i) - Reductions[i] = int((21.9 + std::log(Threads.size()) / 2) * std::log(i)); + Reductions[i] = int((21.5 + std::log(Threads.size()) / 2) * std::log(i)); } @@ -303,10 +303,10 @@ void Thread::search() { multiPV = std::min(multiPV, rootMoves.size()); - complexityAverage.set(232, 1); + complexityAverage.set(190, 1); trend = SCORE_ZERO; - optimism[ us] = Value(25); + optimism[ us] = Value(34); optimism[~us] = -optimism[us]; int searchAgainCounter = 0; @@ -349,16 +349,16 @@ void Thread::search() { if (rootDepth >= 4) { Value prev = rootMoves[pvIdx].averageScore; - delta = Value(17) + int(prev) * prev / 16384; + delta = Value(16) + int(prev) * prev / 16384; alpha = std::max(prev - delta,-VALUE_INFINITE); beta = std::min(prev + delta, VALUE_INFINITE); // Adjust trend and optimism based on root move's previousScore - int tr = sigmoid(prev, 0, 0, 147, 113, 1); + int tr = sigmoid(prev, 6, 13, 96, 110, 1); trend = (us == WHITE ? make_score(tr, tr / 2) : -make_score(tr, tr / 2)); - int opt = sigmoid(prev, 0, 25, 147, 14464, 256); + int opt = sigmoid(prev, 7, 21, 94, 14786, 221); optimism[ us] = Value(opt); optimism[~us] = -optimism[us]; } @@ -413,7 +413,7 @@ void Thread::search() { else break; - delta += delta / 4 + 5; + delta += delta / 4 + 3; assert(alpha >= -VALUE_INFINITE && beta <= VALUE_INFINITE); } @@ -459,17 +459,17 @@ void Thread::search() { && !Threads.stop && !mainThread->stopOnPonderhit) { - double fallingEval = (142 + 12 * (mainThread->bestPreviousAverageScore - bestValue) - + 6 * (mainThread->iterValue[iterIdx] - bestValue)) / 825.0; + double fallingEval = (87 + 12 * (mainThread->bestPreviousAverageScore - bestValue) + + 6 * (mainThread->iterValue[iterIdx] - bestValue)) / 777.20; fallingEval = std::clamp(fallingEval, 0.5, 1.5); // If the bestMove is stable over several iterations, reduce time accordingly - timeReduction = lastBestMoveDepth + 9 < completedDepth ? 1.92 : 0.95; - double reduction = (1.47 + mainThread->previousTimeReduction) / (2.32 * timeReduction); + timeReduction = lastBestMoveDepth + 8 < completedDepth ? 1.70 : 0.91; + double reduction = (1.59 + mainThread->previousTimeReduction) / (2.33 * timeReduction); double bestMoveInstability = 1.073 + std::max(1.0, 2.25 - 9.9 / rootDepth) * totBestMoveChanges / Threads.size(); int complexity = mainThread->complexityAverage.value(); - double complexPosition = std::clamp(1.0 + (complexity - 232) / 1750.0, 0.5, 1.5); + double complexPosition = std::clamp(1.0 + (complexity - 312) / 1750.0, 0.5, 1.5); double totalTime = Time.optimum() * fallingEval * reduction * bestMoveInstability * complexPosition; @@ -490,7 +490,7 @@ void Thread::search() { } else if ( Threads.increaseDepth && !mainThread->ponder - && Time.elapsed() > totalTime * 0.58) + && Time.elapsed() > totalTime * 0.55) Threads.increaseDepth = false; else Threads.increaseDepth = true; @@ -788,19 +788,19 @@ namespace { // Step 8. Futility pruning: child node (~25 Elo). // The depth condition is important for mate finding. if ( !ss->ttPv - && depth < 9 + && depth < 8 && eval - futility_margin(depth, improving) - (ss-1)->statScore / 256 >= beta && eval >= beta - && eval < 15000) // 50% larger than VALUE_KNOWN_WIN, but smaller than TB wins. + && eval < 17548) // 50% larger than VALUE_KNOWN_WIN, but smaller than TB wins. return eval; // Step 9. Null move search with verification search (~22 Elo) if ( !PvNode && (ss-1)->currentMove != MOVE_NULL - && (ss-1)->statScore < 23767 + && (ss-1)->statScore < 13706 && eval >= beta && eval >= ss->staticEval - && ss->staticEval >= beta - 20 * depth - improvement / 15 + 204 + complexity / 25 + && ss->staticEval >= beta - 19 * depth - improvement / 15 + 200 + complexity / 25 && !excludedMove && pos.non_pawn_material(us) && (ss->ply >= thisThread->nmpMinPly || us != thisThread->nmpColor)) @@ -844,13 +844,13 @@ namespace { } } - probCutBeta = beta + 209 - 44 * improving; + probCutBeta = beta + 229 - 47 * improving; // Step 10. ProbCut (~4 Elo) // If we have a good enough capture and a reduced search returns a value // much above beta, we can (almost) safely prune the previous move. if ( !PvNode - && depth > 4 + && depth > 3 && abs(beta) < VALUE_TB_WIN_IN_MAX_PLY // if value from transposition table is lower than probCutBeta, don't attempt probCut // there and in further interactions with transposition table cutoff depth is set to depth - 3 @@ -871,7 +871,6 @@ namespace { if (move != excludedMove && pos.legal(move)) { assert(pos.capture_or_promotion(move)); - assert(depth >= 5); captureOrPromotion = true; @@ -909,19 +908,19 @@ namespace { // Step 11. If the position is not in TT, decrease depth by 2 or 1 depending on node type (~3 Elo) if ( PvNode - && depth >= 6 + && depth >= 4 && !ttMove) depth -= 2; if ( cutNode - && depth >= 9 + && depth >= 7 && !ttMove) depth--; moves_loop: // When in check, search starts here // Step 12. A small Probcut idea, when we are in check (~0 Elo) - probCutBeta = beta + 409; + probCutBeta = beta + 401; if ( ss->inCheck && !PvNode && depth >= 4 @@ -1017,12 +1016,12 @@ moves_loop: // When in check, search starts here && !PvNode && lmrDepth < 6 && !ss->inCheck - && ss->staticEval + 342 + 238 * lmrDepth + PieceValue[EG][pos.piece_on(to_sq(move))] + && ss->staticEval + 392 + 207 * lmrDepth + PieceValue[EG][pos.piece_on(to_sq(move))] + captureHistory[movedPiece][to_sq(move)][type_of(pos.piece_on(to_sq(move)))] / 8 < alpha) continue; // SEE based pruning (~9 Elo) - if (!pos.see_ge(move, Value(-217) * depth)) + if (!pos.see_ge(move, Value(-200) * depth)) continue; } else @@ -1040,12 +1039,12 @@ moves_loop: // When in check, search starts here // Futility pruning: parent node (~9 Elo) if ( !ss->inCheck - && lmrDepth < 8 - && ss->staticEval + 138 + 137 * lmrDepth + history / 64 <= alpha) + && lmrDepth < 11 + && ss->staticEval + 131 + 137 * lmrDepth + history / 64 <= alpha) continue; // Prune moves with negative SEE (~3 Elo) - if (!pos.see_ge(move, Value(-21 * lmrDepth * lmrDepth - 21 * lmrDepth))) + if (!pos.see_ge(move, Value(-25 * lmrDepth * lmrDepth - 29 * lmrDepth))) continue; } } @@ -1081,7 +1080,7 @@ moves_loop: // When in check, search starts here // Avoid search explosion by limiting the number of double extensions if ( !PvNode - && value < singularBeta - 75 + && value < singularBeta - 71 && ss->doubleExtensions <= 6) extension = 2; } @@ -1101,15 +1100,15 @@ moves_loop: // When in check, search starts here // Check extensions (~1 Elo) else if ( givesCheck - && depth > 6 - && abs(ss->staticEval) > 100) + && depth > 7 + && abs(ss->staticEval) > 128) extension = 1; // Quiet ttMove extensions (~0 Elo) else if ( PvNode && move == ttMove && move == ss->killers[0] - && (*contHist[0])[movedPiece][to_sq(move)] >= 10000) + && (*contHist[0])[movedPiece][to_sq(move)] >= 8932) extension = 1; } @@ -1136,8 +1135,8 @@ moves_loop: // When in check, search starts here // We use various heuristics for the sons of a node after the first son has // been searched. In general we would like to reduce them, but there are many // cases where we extend a son if it has good chances to be "interesting". - if ( depth >= 3 - && moveCount > 1 + 2 * rootNode + if ( depth >= 2 + && moveCount > 1 + rootNode && ( !ss->ttPv || !captureOrPromotion || (cutNode && (ss-1)->moveCount > 1))) @@ -1146,7 +1145,7 @@ moves_loop: // When in check, search starts here // Decrease reduction at some PvNodes (~2 Elo) if ( PvNode - && bestMoveCount <= 3) + && bestMoveCount <= 4) r--; // Decrease reduction if position is or has been on the PV @@ -1156,7 +1155,7 @@ moves_loop: // When in check, search starts here r -= 2; // Decrease reduction if opponent's move count is high (~1 Elo) - if ((ss-1)->moveCount > 13) + if ((ss-1)->moveCount > 7) r--; // Increase reduction for cut nodes (~3 Elo) @@ -1171,18 +1170,18 @@ moves_loop: // When in check, search starts here + (*contHist[0])[movedPiece][to_sq(move)] + (*contHist[1])[movedPiece][to_sq(move)] + (*contHist[3])[movedPiece][to_sq(move)] - - 4923; + - 4142; // Decrease/increase reduction for moves with a good/bad history (~30 Elo) - r -= ss->statScore / 14721; + r -= ss->statScore / 15328; // In general we want to cap the LMR depth search at newDepth. But if reductions // are really negative and movecount is low, we allow this move to be searched // deeper than the first move (this may lead to hidden double extensions). int deeper = r >= -1 ? 0 : moveCount <= 5 ? 2 - : PvNode && depth > 6 ? 1 - : cutNode && moveCount <= 7 ? 1 + : PvNode && depth > 4 ? 1 + : cutNode && moveCount <= 5 ? 1 : 0; Depth d = std::clamp(newDepth - r, 1, newDepth + deeper); @@ -1191,7 +1190,7 @@ moves_loop: // When in check, search starts here // If the son is reduced and fails high it will be re-searched at full depth doFullDepthSearch = value > alpha && d < newDepth; - doDeeperSearch = value > (alpha + 62 + 20 * (newDepth - d)); + doDeeperSearch = value > (alpha + 80 + 20 * (newDepth - d)); didLMR = true; } else @@ -1212,7 +1211,7 @@ moves_loop: // When in check, search starts here : -stat_bonus(newDepth); if (captureOrPromotion) - bonus /= 4; + bonus /= 5; update_continuation_histories(ss, movedPiece, to_sq(move), bonus); } @@ -1343,7 +1342,7 @@ moves_loop: // When in check, search starts here //or fail low was really bad bool extraBonus = PvNode || cutNode - || bestValue < alpha - 94 * depth; + || bestValue < alpha - 99 * depth; update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, stat_bonus(depth) * (1 + extraBonus)); } @@ -1474,7 +1473,7 @@ moves_loop: // When in check, search starts here if (PvNode && bestValue > alpha) alpha = bestValue; - futilityBase = bestValue + 155; + futilityBase = bestValue + 127; } const PieceToHistory* contHist[] = { (ss-1)->continuationHistory, (ss-2)->continuationHistory, From cb9c2594fcedc881ae8f8bfbfdf130cf89840e4c Mon Sep 17 00:00:00 2001 From: Tomasz Sobczyk Date: Sat, 27 Nov 2021 15:17:02 +0100 Subject: [PATCH 086/105] Update architecture to "SFNNv4". Update network to nn-6877cd24400e.nnue. Architecture: The diagram of the "SFNNv4" architecture: https://user-images.githubusercontent.com/8037982/153455685-cbe3a038-e158-4481-844d-9d5fccf5c33a.png The most important architectural changes are the following: * 1024x2 [activated] neurons are pairwise, elementwise multiplied (not quite pairwise due to implementation details, see diagram), which introduces a non-linearity that exhibits similar benefits to previously tested sigmoid activation (quantmoid4), while being slightly faster. * The following layer has therefore 2x less inputs, which we compensate by having 2 more outputs. It is possible that reducing the number of outputs might be beneficial (as we had it as low as 8 before). The layer is now 1024->16. * The 16 outputs are split into 15 and 1. The 1-wide output is added to the network output (after some necessary scaling due to quantization differences). The 15-wide is activated and follows the usual path through a set of linear layers. The additional 1-wide output is at least neutral, but has shown a slightly positive trend in training compared to networks without it (all 16 outputs through the usual path), and allows possibly an additional stage of lazy evaluation to be introduced in the future. Additionally, the inference code was rewritten and no longer uses a recursive implementation. This was necessitated by the splitting of the 16-wide intermediate result into two, which was impossible to do with the old implementation with ugly hacks. This is hopefully overall for the better. First session: The first session was training a network from scratch (random initialization). The exact trainer used was slightly different (older) from the one used in the second session, but it should not have a measurable effect. The purpose of this session is to establish a strong network base for the second session. Small deviations in strength do not harm the learnability in the second session. The training was done using the following command: python3 train.py \ /home/sopel/nnue/nnue-pytorch-training/data/nodes5000pv2_UHO.binpack \ /home/sopel/nnue/nnue-pytorch-training/data/nodes5000pv2_UHO.binpack \ --gpus "$3," \ --threads 4 \ --num-workers 4 \ --batch-size 16384 \ --progress_bar_refresh_rate 20 \ --random-fen-skipping 3 \ --features=HalfKAv2_hm^ \ --lambda=1.0 \ --gamma=0.992 \ --lr=8.75e-4 \ --max_epochs=400 \ --default_root_dir ../nnue-pytorch-training/experiment_$1/run_$2 Every 20th net was saved and its playing strength measured against some baseline at 25k nodes per move with pure NNUE evaluation (modified binary). The exact setup is not important as long as it's consistent. The purpose is to sift good candidates from bad ones. The dataset can be found https://drive.google.com/file/d/1UQdZN_LWQ265spwTBwDKo0t1WjSJKvWY/view Second session: The second training session was done starting from the best network (as determined by strength testing) from the first session. It is important that it's resumed from a .pt model and NOT a .ckpt model. The conversion can be performed directly using serialize.py The LR schedule was modified to use gamma=0.995 instead of gamma=0.992 and LR=4.375e-4 instead of LR=8.75e-4 to flatten the LR curve and allow for longer training. The training was then running for 800 epochs instead of 400 (though it's possibly mostly noise after around epoch 600). The training was done using the following command: The training was done using the following command: python3 train.py \ /data/sopel/nnue/nnue-pytorch-training/data/T60T70wIsRightFarseerT60T74T75T76.binpack \ /data/sopel/nnue/nnue-pytorch-training/data/T60T70wIsRightFarseerT60T74T75T76.binpack \ --gpus "$3," \ --threads 4 \ --num-workers 4 \ --batch-size 16384 \ --progress_bar_refresh_rate 20 \ --random-fen-skipping 3 \ --features=HalfKAv2_hm^ \ --lambda=1.0 \ --gamma=0.995 \ --lr=4.375e-4 \ --max_epochs=800 \ --resume-from-model /data/sopel/nnue/nnue-pytorch-training/data/exp295/nn-epoch399.pt \ --default_root_dir ../nnue-pytorch-training/experiment_$1/run_$run_id In particular note that we now use lambda=1.0 instead of lambda=0.8 (previous nets), because tests show that WDL-skipping introduced by vondele performs better with lambda=1.0. Nets were being saved every 20th epoch. In total 16 runs were made with these settings and the best nets chosen according to playing strength at 25k nodes per move with pure NNUE evaluation - these are the 4 nets that have been put on fishtest. The dataset can be found either at ftp://ftp.chessdb.cn/pub/sopel/data_sf/T60T70wIsRightFarseerT60T74T75T76.binpack in its entirety (download might be painfully slow because hosted in China) or can be assembled in the following way: Get the https://github.com/official-stockfish/Stockfish/blob/5640ad48ae5881223b868362c1cbeb042947f7b4/script/interleave_binpacks.py script. Download T60T70wIsRightFarseer.binpack https://drive.google.com/file/d/1_sQoWBl31WAxNXma2v45004CIVltytP8/view Download farseerT74.binpack http://trainingdata.farseer.org/T74-May13-End.7z Download farseerT75.binpack http://trainingdata.farseer.org/T75-June3rd-End.7z Download farseerT76.binpack http://trainingdata.farseer.org/T76-Nov10th-End.7z Run python3 interleave_binpacks.py T60T70wIsRightFarseer.binpack farseerT74.binpack farseerT75.binpack farseerT76.binpack T60T70wIsRightFarseerT60T74T75T76.binpack Tests: STC: https://tests.stockfishchess.org/tests/view/6203fb85d71106ed12a407b7 LLR: 2.94 (-2.94,2.94) <0.00,2.50> Total: 16952 W: 4775 L: 4521 D: 7656 Ptnml(0-2): 133, 1818, 4318, 2076, 131 LTC: https://tests.stockfishchess.org/tests/view/62041e68d71106ed12a40e85 LLR: 2.94 (-2.94,2.94) <0.50,3.00> Total: 14944 W: 4138 L: 3907 D: 6899 Ptnml(0-2): 21, 1499, 4202, 1728, 22 closes https://github.com/official-stockfish/Stockfish/pull/3927 Bench: 4919707 --- src/evaluate.h | 2 +- src/nnue/evaluate_nnue.cpp | 17 +-- src/nnue/layers/affine_transform.h | 91 +++++------- src/nnue/layers/clipped_relu.h | 35 ++--- src/nnue/layers/input_slice.h | 73 ---------- src/nnue/nnue_architecture.h | 107 +++++++++++--- src/nnue/nnue_feature_transformer.h | 210 +++++++++++++--------------- 7 files changed, 235 insertions(+), 300 deletions(-) delete mode 100644 src/nnue/layers/input_slice.h diff --git a/src/evaluate.h b/src/evaluate.h index 57a7687d..1934c9bd 100644 --- a/src/evaluate.h +++ b/src/evaluate.h @@ -39,7 +39,7 @@ namespace Eval { // The default net name MUST follow the format nn-[SHA256 first 12 digits].nnue // for the build process (profile-build and fishtest) to work. Do not change the // name of the macro, as it is used in the Makefile. - #define EvalFileDefaultName "nn-ac07bd334b62.nnue" + #define EvalFileDefaultName "nn-6877cd24400e.nnue" namespace NNUE { diff --git a/src/nnue/evaluate_nnue.cpp b/src/nnue/evaluate_nnue.cpp index 862b2003..0fd58462 100644 --- a/src/nnue/evaluate_nnue.cpp +++ b/src/nnue/evaluate_nnue.cpp @@ -148,22 +148,18 @@ namespace Stockfish::Eval::NNUE { #if defined(ALIGNAS_ON_STACK_VARIABLES_BROKEN) TransformedFeatureType transformedFeaturesUnaligned[ FeatureTransformer::BufferSize + alignment / sizeof(TransformedFeatureType)]; - char bufferUnaligned[Network::BufferSize + alignment]; auto* transformedFeatures = align_ptr_up(&transformedFeaturesUnaligned[0]); - auto* buffer = align_ptr_up(&bufferUnaligned[0]); #else alignas(alignment) TransformedFeatureType transformedFeatures[FeatureTransformer::BufferSize]; - alignas(alignment) char buffer[Network::BufferSize]; #endif ASSERT_ALIGNED(transformedFeatures, alignment); - ASSERT_ALIGNED(buffer, alignment); const std::size_t bucket = (pos.count() - 1) / 4; const auto psqt = featureTransformer->transform(pos, transformedFeatures, bucket); - const auto positional = network[bucket]->propagate(transformedFeatures, buffer)[0]; + const auto positional = network[bucket]->propagate(transformedFeatures); // Give more value to positional evaluation when adjusted flag is set if (adjusted) @@ -190,27 +186,20 @@ namespace Stockfish::Eval::NNUE { #if defined(ALIGNAS_ON_STACK_VARIABLES_BROKEN) TransformedFeatureType transformedFeaturesUnaligned[ FeatureTransformer::BufferSize + alignment / sizeof(TransformedFeatureType)]; - char bufferUnaligned[Network::BufferSize + alignment]; auto* transformedFeatures = align_ptr_up(&transformedFeaturesUnaligned[0]); - auto* buffer = align_ptr_up(&bufferUnaligned[0]); #else alignas(alignment) TransformedFeatureType transformedFeatures[FeatureTransformer::BufferSize]; - alignas(alignment) char buffer[Network::BufferSize]; #endif ASSERT_ALIGNED(transformedFeatures, alignment); - ASSERT_ALIGNED(buffer, alignment); NnueEvalTrace t{}; t.correctBucket = (pos.count() - 1) / 4; for (std::size_t bucket = 0; bucket < LayerStacks; ++bucket) { - const auto psqt = featureTransformer->transform(pos, transformedFeatures, bucket); - const auto output = network[bucket]->propagate(transformedFeatures, buffer); - - int materialist = psqt; - int positional = output[0]; + const auto materialist = featureTransformer->transform(pos, transformedFeatures, bucket); + const auto positional = network[bucket]->propagate(transformedFeatures); t.psqt[bucket] = static_cast( materialist / OutputScale ); t.positional[bucket] = static_cast( positional / OutputScale ); diff --git a/src/nnue/layers/affine_transform.h b/src/nnue/layers/affine_transform.h index 4e85a5fe..22451915 100644 --- a/src/nnue/layers/affine_transform.h +++ b/src/nnue/layers/affine_transform.h @@ -63,19 +63,17 @@ namespace Stockfish::Eval::NNUE::Layers { { # if defined(USE_SSE2) // At least a multiple of 16, with SSE2. - static_assert(PaddedInputDimensions % 16 == 0); - constexpr IndexType NumChunks = PaddedInputDimensions / 16; + constexpr IndexType NumChunks = ceil_to_multiple(InputDimensions, 16) / 16; const __m128i Zeros = _mm_setzero_si128(); const auto inputVector = reinterpret_cast(input); # elif defined(USE_MMX) - static_assert(InputDimensions % 8 == 0); - constexpr IndexType NumChunks = InputDimensions / 8; + constexpr IndexType NumChunks = ceil_to_multiple(InputDimensions, 8) / 8; const __m64 Zeros = _mm_setzero_si64(); const auto inputVector = reinterpret_cast(input); # elif defined(USE_NEON) - constexpr IndexType NumChunks = (InputDimensions + 15) / 16; + constexpr IndexType NumChunks = ceil_to_multiple(InputDimensions, 16) / 16; const auto inputVector = reinterpret_cast(input); # endif @@ -150,24 +148,27 @@ namespace Stockfish::Eval::NNUE::Layers { } #endif - template + template class AffineTransform; // A specialization for large inputs. - template - class AffineTransform= 2*64-1)>> { + template + class AffineTransform(InDims, MaxSimdWidth) >= 2*64)>> { public: // Input/output type - using InputType = typename PreviousLayer::OutputType; + using InputType = std::uint8_t; using OutputType = std::int32_t; - static_assert(std::is_same::value, ""); // Number of input/output dimensions - static constexpr IndexType InputDimensions = PreviousLayer::OutputDimensions; + static constexpr IndexType InputDimensions = InDims; static constexpr IndexType OutputDimensions = OutDims; static constexpr IndexType PaddedInputDimensions = ceil_to_multiple(InputDimensions, MaxSimdWidth); + static constexpr IndexType PaddedOutputDimensions = + ceil_to_multiple(OutputDimensions, MaxSimdWidth); + + using OutputBuffer = OutputType[PaddedOutputDimensions]; static_assert(PaddedInputDimensions >= 128, "Something went wrong. This specialization should not have been chosen."); @@ -202,20 +203,12 @@ namespace Stockfish::Eval::NNUE::Layers { static_assert(OutputDimensions % NumOutputRegs == 0); - // Size of forward propagation buffer used in this layer - static constexpr std::size_t SelfBufferSize = - ceil_to_multiple(OutputDimensions * sizeof(OutputType), CacheLineSize); - - // Size of the forward propagation buffer used from the input layer to this layer - static constexpr std::size_t BufferSize = - PreviousLayer::BufferSize + SelfBufferSize; - // Hash value embedded in the evaluation file - static constexpr std::uint32_t get_hash_value() { + static constexpr std::uint32_t get_hash_value(std::uint32_t prevHash) { std::uint32_t hashValue = 0xCC03DAE4u; hashValue += OutputDimensions; - hashValue ^= PreviousLayer::get_hash_value() >> 1; - hashValue ^= PreviousLayer::get_hash_value() << 31; + hashValue ^= prevHash >> 1; + hashValue ^= prevHash << 31; return hashValue; } @@ -242,7 +235,6 @@ namespace Stockfish::Eval::NNUE::Layers { // Read network parameters bool read_parameters(std::istream& stream) { - if (!previousLayer.read_parameters(stream)) return false; for (std::size_t i = 0; i < OutputDimensions; ++i) biases[i] = read_little_endian(stream); @@ -254,7 +246,6 @@ namespace Stockfish::Eval::NNUE::Layers { // Write network parameters bool write_parameters(std::ostream& stream) const { - if (!previousLayer.write_parameters(stream)) return false; for (std::size_t i = 0; i < OutputDimensions; ++i) write_little_endian(stream, biases[i]); @@ -266,10 +257,7 @@ namespace Stockfish::Eval::NNUE::Layers { // Forward propagation const OutputType* propagate( - const TransformedFeatureType* transformedFeatures, char* buffer) const { - const auto input = previousLayer.propagate( - transformedFeatures, buffer + SelfBufferSize); - OutputType* output = reinterpret_cast(buffer); + const InputType* input, OutputType* output) const { #if defined (USE_AVX512) using acc_vec_t = __m512i; @@ -312,7 +300,6 @@ namespace Stockfish::Eval::NNUE::Layers { #if defined (USE_SSSE3) || defined (USE_NEON) const in_vec_t* invec = reinterpret_cast(input); - // Perform accumulation to registers for each big block for (IndexType bigBlock = 0; bigBlock < NumBigBlocks; ++bigBlock) { @@ -377,26 +364,28 @@ namespace Stockfish::Eval::NNUE::Layers { using BiasType = OutputType; using WeightType = std::int8_t; - PreviousLayer previousLayer; - alignas(CacheLineSize) BiasType biases[OutputDimensions]; alignas(CacheLineSize) WeightType weights[OutputDimensions * PaddedInputDimensions]; }; - template - class AffineTransform> { + template + class AffineTransform(InDims, MaxSimdWidth) < 2*64)>> { public: // Input/output type - using InputType = typename PreviousLayer::OutputType; + // Input/output type + using InputType = std::uint8_t; using OutputType = std::int32_t; - static_assert(std::is_same::value, ""); // Number of input/output dimensions - static constexpr IndexType InputDimensions = - PreviousLayer::OutputDimensions; + static constexpr IndexType InputDimensions = InDims; static constexpr IndexType OutputDimensions = OutDims; + static constexpr IndexType PaddedInputDimensions = - ceil_to_multiple(InputDimensions, MaxSimdWidth); + ceil_to_multiple(InputDimensions, MaxSimdWidth); + static constexpr IndexType PaddedOutputDimensions = + ceil_to_multiple(OutputDimensions, MaxSimdWidth); + + using OutputBuffer = OutputType[PaddedOutputDimensions]; static_assert(PaddedInputDimensions < 128, "Something went wrong. This specialization should not have been chosen."); @@ -405,20 +394,12 @@ namespace Stockfish::Eval::NNUE::Layers { static constexpr const IndexType InputSimdWidth = SimdWidth; #endif - // Size of forward propagation buffer used in this layer - static constexpr std::size_t SelfBufferSize = - ceil_to_multiple(OutputDimensions * sizeof(OutputType), CacheLineSize); - - // Size of the forward propagation buffer used from the input layer to this layer - static constexpr std::size_t BufferSize = - PreviousLayer::BufferSize + SelfBufferSize; - // Hash value embedded in the evaluation file - static constexpr std::uint32_t get_hash_value() { + static constexpr std::uint32_t get_hash_value(std::uint32_t prevHash) { std::uint32_t hashValue = 0xCC03DAE4u; hashValue += OutputDimensions; - hashValue ^= PreviousLayer::get_hash_value() >> 1; - hashValue ^= PreviousLayer::get_hash_value() << 31; + hashValue ^= prevHash >> 1; + hashValue ^= prevHash << 31; return hashValue; } @@ -441,7 +422,6 @@ namespace Stockfish::Eval::NNUE::Layers { // Read network parameters bool read_parameters(std::istream& stream) { - if (!previousLayer.read_parameters(stream)) return false; for (std::size_t i = 0; i < OutputDimensions; ++i) biases[i] = read_little_endian(stream); for (std::size_t i = 0; i < OutputDimensions * PaddedInputDimensions; ++i) @@ -452,7 +432,6 @@ namespace Stockfish::Eval::NNUE::Layers { // Write network parameters bool write_parameters(std::ostream& stream) const { - if (!previousLayer.write_parameters(stream)) return false; for (std::size_t i = 0; i < OutputDimensions; ++i) write_little_endian(stream, biases[i]); @@ -463,10 +442,7 @@ namespace Stockfish::Eval::NNUE::Layers { } // Forward propagation const OutputType* propagate( - const TransformedFeatureType* transformedFeatures, char* buffer) const { - const auto input = previousLayer.propagate( - transformedFeatures, buffer + SelfBufferSize); - const auto output = reinterpret_cast(buffer); + const InputType* input, OutputType* output) const { #if defined (USE_AVX2) using vec_t = __m256i; @@ -491,12 +467,11 @@ namespace Stockfish::Eval::NNUE::Layers { #if defined (USE_SSSE3) const auto inputVector = reinterpret_cast(input); - static_assert(InputDimensions % 8 == 0); static_assert(OutputDimensions % OutputSimdWidth == 0 || OutputDimensions == 1); if constexpr (OutputDimensions % OutputSimdWidth == 0) { - constexpr IndexType NumChunks = InputDimensions / 4; + constexpr IndexType NumChunks = ceil_to_multiple(InputDimensions, 8) / 4; constexpr IndexType NumRegs = OutputDimensions / OutputSimdWidth; const auto input32 = reinterpret_cast(input); @@ -555,8 +530,6 @@ namespace Stockfish::Eval::NNUE::Layers { using BiasType = OutputType; using WeightType = std::int8_t; - PreviousLayer previousLayer; - alignas(CacheLineSize) BiasType biases[OutputDimensions]; alignas(CacheLineSize) WeightType weights[OutputDimensions * PaddedInputDimensions]; }; diff --git a/src/nnue/layers/clipped_relu.h b/src/nnue/layers/clipped_relu.h index 0da5e821..ffd2e3b7 100644 --- a/src/nnue/layers/clipped_relu.h +++ b/src/nnue/layers/clipped_relu.h @@ -26,51 +26,41 @@ namespace Stockfish::Eval::NNUE::Layers { // Clipped ReLU - template + template class ClippedReLU { public: // Input/output type - using InputType = typename PreviousLayer::OutputType; + using InputType = std::int32_t; using OutputType = std::uint8_t; - static_assert(std::is_same::value, ""); // Number of input/output dimensions - static constexpr IndexType InputDimensions = PreviousLayer::OutputDimensions; + static constexpr IndexType InputDimensions = InDims; static constexpr IndexType OutputDimensions = InputDimensions; static constexpr IndexType PaddedOutputDimensions = ceil_to_multiple(OutputDimensions, 32); - // Size of forward propagation buffer used in this layer - static constexpr std::size_t SelfBufferSize = - ceil_to_multiple(OutputDimensions * sizeof(OutputType), CacheLineSize); - - // Size of the forward propagation buffer used from the input layer to this layer - static constexpr std::size_t BufferSize = - PreviousLayer::BufferSize + SelfBufferSize; + using OutputBuffer = OutputType[PaddedOutputDimensions]; // Hash value embedded in the evaluation file - static constexpr std::uint32_t get_hash_value() { + static constexpr std::uint32_t get_hash_value(std::uint32_t prevHash) { std::uint32_t hashValue = 0x538D24C7u; - hashValue += PreviousLayer::get_hash_value(); + hashValue += prevHash; return hashValue; } // Read network parameters - bool read_parameters(std::istream& stream) { - return previousLayer.read_parameters(stream); + bool read_parameters(std::istream&) { + return true; } // Write network parameters - bool write_parameters(std::ostream& stream) const { - return previousLayer.write_parameters(stream); + bool write_parameters(std::ostream&) const { + return true; } // Forward propagation const OutputType* propagate( - const TransformedFeatureType* transformedFeatures, char* buffer) const { - const auto input = previousLayer.propagate( - transformedFeatures, buffer + SelfBufferSize); - const auto output = reinterpret_cast(buffer); + const InputType* input, OutputType* output) const { #if defined(USE_AVX2) if constexpr (InputDimensions % SimdWidth == 0) { @@ -191,9 +181,6 @@ namespace Stockfish::Eval::NNUE::Layers { return output; } - - private: - PreviousLayer previousLayer; }; } // namespace Stockfish::Eval::NNUE::Layers diff --git a/src/nnue/layers/input_slice.h b/src/nnue/layers/input_slice.h deleted file mode 100644 index 8f526b74..00000000 --- a/src/nnue/layers/input_slice.h +++ /dev/null @@ -1,73 +0,0 @@ -/* - Stockfish, a UCI chess playing engine derived from Glaurung 2.1 - Copyright (C) 2004-2022 The Stockfish developers (see AUTHORS file) - - Stockfish is free software: you can redistribute it and/or modify - it under the terms of the GNU General Public License as published by - the Free Software Foundation, either version 3 of the License, or - (at your option) any later version. - - Stockfish is distributed in the hope that it will be useful, - but WITHOUT ANY WARRANTY; without even the implied warranty of - MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - GNU General Public License for more details. - - You should have received a copy of the GNU General Public License - along with this program. If not, see . -*/ - -// NNUE evaluation function layer InputSlice definition - -#ifndef NNUE_LAYERS_INPUT_SLICE_H_INCLUDED -#define NNUE_LAYERS_INPUT_SLICE_H_INCLUDED - -#include "../nnue_common.h" - -namespace Stockfish::Eval::NNUE::Layers { - -// Input layer -template -class InputSlice { - public: - // Need to maintain alignment - static_assert(Offset % MaxSimdWidth == 0, ""); - - // Output type - using OutputType = TransformedFeatureType; - - // Output dimensionality - static constexpr IndexType OutputDimensions = OutDims; - - // Size of forward propagation buffer used from the input layer to this layer - static constexpr std::size_t BufferSize = 0; - - // Hash value embedded in the evaluation file - static constexpr std::uint32_t get_hash_value() { - std::uint32_t hashValue = 0xEC42E90Du; - hashValue ^= OutputDimensions ^ (Offset << 10); - return hashValue; - } - - // Read network parameters - bool read_parameters(std::istream& /*stream*/) { - return true; - } - - // Write network parameters - bool write_parameters(std::ostream& /*stream*/) const { - return true; - } - - // Forward propagation - const OutputType* propagate( - const TransformedFeatureType* transformedFeatures, - char* /*buffer*/) const { - return transformedFeatures + Offset; - } - - private: -}; - -} // namespace Stockfish::Eval::NNUE::Layers - -#endif // #ifndef NNUE_LAYERS_INPUT_SLICE_H_INCLUDED diff --git a/src/nnue/nnue_architecture.h b/src/nnue/nnue_architecture.h index 8867fac7..725b40fb 100644 --- a/src/nnue/nnue_architecture.h +++ b/src/nnue/nnue_architecture.h @@ -25,35 +25,106 @@ #include "features/half_ka_v2_hm.h" -#include "layers/input_slice.h" #include "layers/affine_transform.h" #include "layers/clipped_relu.h" +#include "../misc.h" + namespace Stockfish::Eval::NNUE { - // Input features used in evaluation function - using FeatureSet = Features::HalfKAv2_hm; +// Input features used in evaluation function +using FeatureSet = Features::HalfKAv2_hm; - // Number of input feature dimensions after conversion - constexpr IndexType TransformedFeatureDimensions = 1024; - constexpr IndexType PSQTBuckets = 8; - constexpr IndexType LayerStacks = 8; +// Number of input feature dimensions after conversion +constexpr IndexType TransformedFeatureDimensions = 1024; +constexpr IndexType PSQTBuckets = 8; +constexpr IndexType LayerStacks = 8; - namespace Layers { +struct Network +{ + static constexpr int FC_0_OUTPUTS = 15; + static constexpr int FC_1_OUTPUTS = 32; - // Define network structure - using InputLayer = InputSlice; - using HiddenLayer1 = ClippedReLU>; - using HiddenLayer2 = ClippedReLU>; - using OutputLayer = AffineTransform; + Layers::AffineTransform fc_0; + Layers::ClippedReLU ac_0; + Layers::AffineTransform fc_1; + Layers::ClippedReLU ac_1; + Layers::AffineTransform fc_2; - } // namespace Layers + // Hash value embedded in the evaluation file + static constexpr std::uint32_t get_hash_value() { + // input slice hash + std::uint32_t hashValue = 0xEC42E90Du; + hashValue ^= TransformedFeatureDimensions * 2; - using Network = Layers::OutputLayer; + hashValue = decltype(fc_0)::get_hash_value(hashValue); + hashValue = decltype(ac_0)::get_hash_value(hashValue); + hashValue = decltype(fc_1)::get_hash_value(hashValue); + hashValue = decltype(ac_1)::get_hash_value(hashValue); + hashValue = decltype(fc_2)::get_hash_value(hashValue); - static_assert(TransformedFeatureDimensions % MaxSimdWidth == 0, ""); - static_assert(Network::OutputDimensions == 1, ""); - static_assert(std::is_same::value, ""); + return hashValue; + } + + // Read network parameters + bool read_parameters(std::istream& stream) { + if (!fc_0.read_parameters(stream)) return false; + if (!ac_0.read_parameters(stream)) return false; + if (!fc_1.read_parameters(stream)) return false; + if (!ac_1.read_parameters(stream)) return false; + if (!fc_2.read_parameters(stream)) return false; + return true; + } + + // Read network parameters + bool write_parameters(std::ostream& stream) const { + if (!fc_0.write_parameters(stream)) return false; + if (!ac_0.write_parameters(stream)) return false; + if (!fc_1.write_parameters(stream)) return false; + if (!ac_1.write_parameters(stream)) return false; + if (!fc_2.write_parameters(stream)) return false; + return true; + } + + std::int32_t propagate(const TransformedFeatureType* transformedFeatures) + { + constexpr uint64_t alignment = CacheLineSize; + + struct Buffer + { + alignas(CacheLineSize) decltype(fc_0)::OutputBuffer fc_0_out; + alignas(CacheLineSize) decltype(ac_0)::OutputBuffer ac_0_out; + alignas(CacheLineSize) decltype(fc_1)::OutputBuffer fc_1_out; + alignas(CacheLineSize) decltype(ac_1)::OutputBuffer ac_1_out; + alignas(CacheLineSize) decltype(fc_2)::OutputBuffer fc_2_out; + }; + +#if defined(ALIGNAS_ON_STACK_VARIABLES_BROKEN) + char bufferRaw[sizeof(Buffer) + alignment]; + char* bufferRawAligned = align_ptr_up(&bufferRaw[0]); + Buffer& buffer = *(new (bufferRawAligned) Buffer); +#else + alignas(alignment) Buffer buffer; +#endif + + fc_0.propagate(transformedFeatures, buffer.fc_0_out); + ac_0.propagate(buffer.fc_0_out, buffer.ac_0_out); + fc_1.propagate(buffer.ac_0_out, buffer.fc_1_out); + ac_1.propagate(buffer.fc_1_out, buffer.ac_1_out); + fc_2.propagate(buffer.ac_1_out, buffer.fc_2_out); + + // buffer.fc_0_out[FC_0_OUTPUTS] is such that 1.0 is equal to 127*(1<(&output[offset]); - for (IndexType j = 0; j < NumChunks; ++j) + const IndexType offset = (HalfDimensions / 2) * p; + +#if defined(USE_AVX512) + + constexpr IndexType OutputChunkSize = 512 / 8; + static_assert((HalfDimensions / 2) % OutputChunkSize == 0); + constexpr IndexType NumOutputChunks = HalfDimensions / 2 / OutputChunkSize; + + const __m512i Zero = _mm512_setzero_si512(); + const __m512i One = _mm512_set1_epi16(127); + const __m512i Control = _mm512_setr_epi64(0, 2, 4, 6, 1, 3, 5, 7); + + const __m512i* in0 = reinterpret_cast(&(accumulation[perspectives[p]][0])); + const __m512i* in1 = reinterpret_cast(&(accumulation[perspectives[p]][HalfDimensions / 2])); + __m512i* out = reinterpret_cast< __m512i*>(output + offset); + + for (IndexType j = 0; j < NumOutputChunks; j += 1) { - __m512i sum0 = _mm512_load_si512(&reinterpret_cast - (accumulation[perspectives[p]])[j * 2 + 0]); - __m512i sum1 = _mm512_load_si512(&reinterpret_cast - (accumulation[perspectives[p]])[j * 2 + 1]); + const __m512i sum0a = _mm512_max_epi16(_mm512_min_epi16(in0[j * 2 + 0], One), Zero); + const __m512i sum0b = _mm512_max_epi16(_mm512_min_epi16(in0[j * 2 + 1], One), Zero); + const __m512i sum1a = _mm512_max_epi16(_mm512_min_epi16(in1[j * 2 + 0], One), Zero); + const __m512i sum1b = _mm512_max_epi16(_mm512_min_epi16(in1[j * 2 + 1], One), Zero); - _mm512_store_si512(&out[j], _mm512_permutexvar_epi64(Control, - _mm512_max_epi8(_mm512_packs_epi16(sum0, sum1), Zero))); + const __m512i pa = _mm512_srli_epi16(_mm512_mullo_epi16(sum0a, sum1a), 7); + const __m512i pb = _mm512_srli_epi16(_mm512_mullo_epi16(sum0b, sum1b), 7); + + out[j] = _mm512_permutexvar_epi64(Control, _mm512_packs_epi16(pa, pb)); } - } - return psqt; - #elif defined(USE_AVX2) +#elif defined(USE_AVX2) - constexpr IndexType NumChunks = HalfDimensions / SimdWidth; - constexpr int Control = 0b11011000; - const __m256i Zero = _mm256_setzero_si256(); + constexpr IndexType OutputChunkSize = 256 / 8; + static_assert((HalfDimensions / 2) % OutputChunkSize == 0); + constexpr IndexType NumOutputChunks = HalfDimensions / 2 / OutputChunkSize; - for (IndexType p = 0; p < 2; ++p) - { - const IndexType offset = HalfDimensions * p; - auto out = reinterpret_cast<__m256i*>(&output[offset]); - for (IndexType j = 0; j < NumChunks; ++j) + const __m256i Zero = _mm256_setzero_si256(); + const __m256i One = _mm256_set1_epi16(127); + constexpr int Control = 0b11011000; + + const __m256i* in0 = reinterpret_cast(&(accumulation[perspectives[p]][0])); + const __m256i* in1 = reinterpret_cast(&(accumulation[perspectives[p]][HalfDimensions / 2])); + __m256i* out = reinterpret_cast< __m256i*>(output + offset); + + for (IndexType j = 0; j < NumOutputChunks; j += 1) { - __m256i sum0 = _mm256_load_si256(&reinterpret_cast - (accumulation[perspectives[p]])[j * 2 + 0]); - __m256i sum1 = _mm256_load_si256(&reinterpret_cast - (accumulation[perspectives[p]])[j * 2 + 1]); + const __m256i sum0a = _mm256_max_epi16(_mm256_min_epi16(in0[j * 2 + 0], One), Zero); + const __m256i sum0b = _mm256_max_epi16(_mm256_min_epi16(in0[j * 2 + 1], One), Zero); + const __m256i sum1a = _mm256_max_epi16(_mm256_min_epi16(in1[j * 2 + 0], One), Zero); + const __m256i sum1b = _mm256_max_epi16(_mm256_min_epi16(in1[j * 2 + 1], One), Zero); - _mm256_store_si256(&out[j], _mm256_permute4x64_epi64( - _mm256_max_epi8(_mm256_packs_epi16(sum0, sum1), Zero), Control)); + const __m256i pa = _mm256_srli_epi16(_mm256_mullo_epi16(sum0a, sum1a), 7); + const __m256i pb = _mm256_srli_epi16(_mm256_mullo_epi16(sum0b, sum1b), 7); + + out[j] = _mm256_permute4x64_epi64(_mm256_packs_epi16(pa, pb), Control); } - } - return psqt; - #elif defined(USE_SSE2) +#elif defined(USE_SSE2) - #ifdef USE_SSE41 - constexpr IndexType NumChunks = HalfDimensions / SimdWidth; - const __m128i Zero = _mm_setzero_si128(); - #else - constexpr IndexType NumChunks = HalfDimensions / SimdWidth; - const __m128i k0x80s = _mm_set1_epi8(-128); - #endif + constexpr IndexType OutputChunkSize = 128 / 8; + static_assert((HalfDimensions / 2) % OutputChunkSize == 0); + constexpr IndexType NumOutputChunks = HalfDimensions / 2 / OutputChunkSize; - for (IndexType p = 0; p < 2; ++p) - { - const IndexType offset = HalfDimensions * p; - auto out = reinterpret_cast<__m128i*>(&output[offset]); - for (IndexType j = 0; j < NumChunks; ++j) + const __m128i Zero = _mm_setzero_si128(); + const __m128i One = _mm_set1_epi16(127); + + const __m128i* in0 = reinterpret_cast(&(accumulation[perspectives[p]][0])); + const __m128i* in1 = reinterpret_cast(&(accumulation[perspectives[p]][HalfDimensions / 2])); + __m128i* out = reinterpret_cast< __m128i*>(output + offset); + + for (IndexType j = 0; j < NumOutputChunks; j += 1) { - __m128i sum0 = _mm_load_si128(&reinterpret_cast - (accumulation[perspectives[p]])[j * 2 + 0]); - __m128i sum1 = _mm_load_si128(&reinterpret_cast - (accumulation[perspectives[p]])[j * 2 + 1]); - const __m128i packedbytes = _mm_packs_epi16(sum0, sum1); + const __m128i sum0a = _mm_max_epi16(_mm_min_epi16(in0[j * 2 + 0], One), Zero); + const __m128i sum0b = _mm_max_epi16(_mm_min_epi16(in0[j * 2 + 1], One), Zero); + const __m128i sum1a = _mm_max_epi16(_mm_min_epi16(in1[j * 2 + 0], One), Zero); + const __m128i sum1b = _mm_max_epi16(_mm_min_epi16(in1[j * 2 + 1], One), Zero); - #ifdef USE_SSE41 - _mm_store_si128(&out[j], _mm_max_epi8(packedbytes, Zero)); - #else - _mm_store_si128(&out[j], _mm_subs_epi8(_mm_adds_epi8(packedbytes, k0x80s), k0x80s)); - #endif + const __m128i pa = _mm_srli_epi16(_mm_mullo_epi16(sum0a, sum1a), 7); + const __m128i pb = _mm_srli_epi16(_mm_mullo_epi16(sum0b, sum1b), 7); + + out[j] = _mm_packs_epi16(pa, pb); } - } - return psqt; - #elif defined(USE_MMX) +#elif defined(USE_NEON) - constexpr IndexType NumChunks = HalfDimensions / SimdWidth; - const __m64 k0x80s = _mm_set1_pi8(-128); + constexpr IndexType OutputChunkSize = 128 / 8; + static_assert((HalfDimensions / 2) % OutputChunkSize == 0); + constexpr IndexType NumOutputChunks = HalfDimensions / 2 / OutputChunkSize; - for (IndexType p = 0; p < 2; ++p) - { - const IndexType offset = HalfDimensions * p; - auto out = reinterpret_cast<__m64*>(&output[offset]); - for (IndexType j = 0; j < NumChunks; ++j) + const int16x8_t Zero = vdupq_n_s16(0); + const int16x8_t One = vdupq_n_s16(127); + + const int16x8_t* in0 = reinterpret_cast(&(accumulation[perspectives[p]][0])); + const int16x8_t* in1 = reinterpret_cast(&(accumulation[perspectives[p]][HalfDimensions / 2])); + int8x16_t* out = reinterpret_cast< int8x16_t*>(output + offset); + + for (IndexType j = 0; j < NumOutputChunks; j += 1) { - __m64 sum0 = *(&reinterpret_cast(accumulation[perspectives[p]])[j * 2 + 0]); - __m64 sum1 = *(&reinterpret_cast(accumulation[perspectives[p]])[j * 2 + 1]); - const __m64 packedbytes = _mm_packs_pi16(sum0, sum1); - out[j] = _mm_subs_pi8(_mm_adds_pi8(packedbytes, k0x80s), k0x80s); + const int16x8_t sum0a = vmaxq_s16(vminq_s16(in0[j * 2 + 0], One), Zero); + const int16x8_t sum0b = vmaxq_s16(vminq_s16(in0[j * 2 + 1], One), Zero); + const int16x8_t sum1a = vmaxq_s16(vminq_s16(in1[j * 2 + 0], One), Zero); + const int16x8_t sum1b = vmaxq_s16(vminq_s16(in1[j * 2 + 1], One), Zero); + + const int8x8_t pa = vshrn_n_s16(vmulq_s16(sum0a, sum1a), 7); + const int8x8_t pb = vshrn_n_s16(vmulq_s16(sum0b, sum1b), 7); + + out[j] = vcombine_s8(pa, pb); } - } - _mm_empty(); - return psqt; - #elif defined(USE_NEON) +#else - constexpr IndexType NumChunks = HalfDimensions / (SimdWidth / 2); - const int8x8_t Zero = {0}; - - for (IndexType p = 0; p < 2; ++p) - { - const IndexType offset = HalfDimensions * p; - const auto out = reinterpret_cast(&output[offset]); - - constexpr IndexType UnrollFactor = 16; - static_assert(UnrollFactor % UnrollFactor == 0); - for (IndexType j = 0; j < NumChunks; j += UnrollFactor) - { - int16x8_t sums[UnrollFactor]; - for (IndexType i = 0; i < UnrollFactor; ++i) - sums[i] = reinterpret_cast(accumulation[perspectives[p]])[j+i]; - - for (IndexType i = 0; i < UnrollFactor; ++i) - out[j+i] = vmax_s8(vqmovn_s16(sums[i]), Zero); + for (IndexType j = 0; j < HalfDimensions / 2; ++j) { + BiasType sum0 = accumulation[static_cast(perspectives[p])][j + 0]; + BiasType sum1 = accumulation[static_cast(perspectives[p])][j + HalfDimensions / 2]; + sum0 = std::max(0, std::min(127, sum0)); + sum1 = std::max(0, std::min(127, sum1)); + output[offset + j] = static_cast(sum0 * sum1 / 128); } + +#endif } + return psqt; - #else - - for (IndexType p = 0; p < 2; ++p) - { - const IndexType offset = HalfDimensions * p; - for (IndexType j = 0; j < HalfDimensions; ++j) - { - BiasType sum = accumulation[perspectives[p]][j]; - output[offset + j] = static_cast(std::max(0, std::min(127, sum))); - } - } - return psqt; - - #endif - } // end of function transform() From 3ec6e1d2450183ed4975cf569b5a1286cb9d8369 Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Sat, 12 Feb 2022 20:08:45 +0300 Subject: [PATCH 087/105] Big search tuning (version 2) One more tuning - this one includes newly introduced heuristics and some other parameters that were not included in previous one. Result of 400k games at 20+0.2 "as is". Tuning is continuing since there is probably a lot more elo to gain. STC: https://tests.stockfishchess.org/tests/view/620782edd71106ed12a497d1 LLR: 2.99 (-2.94,2.94) <0.00,2.50> Total: 38504 W: 10260 L: 9978 D: 18266 Ptnml(0-2): 142, 4249, 10230, 4447, 184 LTC: https://tests.stockfishchess.org/tests/view/6207a243d71106ed12a49d07 LLR: 2.94 (-2.94,2.94) <0.50,3.00> Total: 25176 W: 6793 L: 6546 D: 11837 Ptnml(0-2): 20, 2472, 7360, 2713, 23 closes https://github.com/official-stockfish/Stockfish/pull/3931 Bench: 4784796 --- src/search.cpp | 98 +++++++++++++++++++++++++------------------------- 1 file changed, 49 insertions(+), 49 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 5bc9de7b..0b98bb27 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -63,7 +63,7 @@ namespace { // Futility margin Value futility_margin(Depth d, bool improving) { - return Value(171 * (d - improving)); + return Value(147 * (d - improving)); } // Reductions lookup table, initialized at startup @@ -71,7 +71,7 @@ namespace { Depth reduction(bool i, Depth d, int mn, Value delta, Value rootDelta) { int r = Reductions[d] * Reductions[mn]; - return (r + 1575 - int(delta) * 1024 / int(rootDelta)) / 1024 + (!i && r > 1011); + return (r + 1627 - int(delta) * 1024 / int(rootDelta)) / 1024 + (!i && r > 992); } constexpr int futility_move_count(bool improving, Depth depth) { @@ -80,7 +80,7 @@ namespace { // History and stats update bonus, based on depth int stat_bonus(Depth d) { - return std::min((7 * d + 254) * d - 206 , 1990); + return std::min((8 * d + 281) * d - 241 , 1949); } // Add a small random component to draw evaluations to avoid 3-fold blindness @@ -157,7 +157,7 @@ namespace { void Search::init() { for (int i = 1; i < MAX_MOVES; ++i) - Reductions[i] = int((21.5 + std::log(Threads.size()) / 2) * std::log(i)); + Reductions[i] = int((21.14 + std::log(Threads.size()) / 2) * std::log(i)); } @@ -303,10 +303,10 @@ void Thread::search() { multiPV = std::min(multiPV, rootMoves.size()); - complexityAverage.set(190, 1); + complexityAverage.set(211, 1); trend = SCORE_ZERO; - optimism[ us] = Value(34); + optimism[ us] = Value(33); optimism[~us] = -optimism[us]; int searchAgainCounter = 0; @@ -349,16 +349,16 @@ void Thread::search() { if (rootDepth >= 4) { Value prev = rootMoves[pvIdx].averageScore; - delta = Value(16) + int(prev) * prev / 16384; + delta = Value(19) + int(prev) * prev / 18321; alpha = std::max(prev - delta,-VALUE_INFINITE); beta = std::min(prev + delta, VALUE_INFINITE); // Adjust trend and optimism based on root move's previousScore - int tr = sigmoid(prev, 6, 13, 96, 110, 1); + int tr = sigmoid(prev, 4, 11, 92, 119, 1); trend = (us == WHITE ? make_score(tr, tr / 2) : -make_score(tr, tr / 2)); - int opt = sigmoid(prev, 7, 21, 94, 14786, 221); + int opt = sigmoid(prev, 9, 18, 115, 12250, 187); optimism[ us] = Value(opt); optimism[~us] = -optimism[us]; } @@ -413,7 +413,7 @@ void Thread::search() { else break; - delta += delta / 4 + 3; + delta += delta / 4 + 2; assert(alpha >= -VALUE_INFINITE && beta <= VALUE_INFINITE); } @@ -459,17 +459,17 @@ void Thread::search() { && !Threads.stop && !mainThread->stopOnPonderhit) { - double fallingEval = (87 + 12 * (mainThread->bestPreviousAverageScore - bestValue) - + 6 * (mainThread->iterValue[iterIdx] - bestValue)) / 777.20; + double fallingEval = (66 + 12 * (mainThread->bestPreviousAverageScore - bestValue) + + 6 * (mainThread->iterValue[iterIdx] - bestValue)) / 809.70; fallingEval = std::clamp(fallingEval, 0.5, 1.5); // If the bestMove is stable over several iterations, reduce time accordingly - timeReduction = lastBestMoveDepth + 8 < completedDepth ? 1.70 : 0.91; - double reduction = (1.59 + mainThread->previousTimeReduction) / (2.33 * timeReduction); + timeReduction = lastBestMoveDepth + 8 < completedDepth ? 1.73 : 0.94; + double reduction = (1.66 + mainThread->previousTimeReduction) / (2.35 * timeReduction); double bestMoveInstability = 1.073 + std::max(1.0, 2.25 - 9.9 / rootDepth) * totBestMoveChanges / Threads.size(); int complexity = mainThread->complexityAverage.value(); - double complexPosition = std::clamp(1.0 + (complexity - 312) / 1750.0, 0.5, 1.5); + double complexPosition = std::clamp(1.0 + (complexity - 293) / 1525.0, 0.5, 1.5); double totalTime = Time.optimum() * fallingEval * reduction * bestMoveInstability * complexPosition; @@ -490,7 +490,7 @@ void Thread::search() { } else if ( Threads.increaseDepth && !mainThread->ponder - && Time.elapsed() > totalTime * 0.55) + && Time.elapsed() > totalTime * 0.49) Threads.increaseDepth = false; else Threads.increaseDepth = true; @@ -766,7 +766,7 @@ namespace { // margin and the improving flag are used in various pruning heuristics. improvement = (ss-2)->staticEval != VALUE_NONE ? ss->staticEval - (ss-2)->staticEval : (ss-4)->staticEval != VALUE_NONE ? ss->staticEval - (ss-4)->staticEval - : 200; + : 184; improving = improvement > 0; complexity = abs(ss->staticEval - (us == WHITE ? eg_value(pos.psq_score()) : -eg_value(pos.psq_score()))); @@ -778,7 +778,7 @@ namespace { // return a fail low. if ( !PvNode && depth <= 6 - && eval < alpha - 400 - 300 * depth * depth) + && eval < alpha - 486 - 314 * depth * depth) { value = qsearch(pos, ss, alpha - 1, alpha); if (value < alpha) @@ -791,16 +791,16 @@ namespace { && depth < 8 && eval - futility_margin(depth, improving) - (ss-1)->statScore / 256 >= beta && eval >= beta - && eval < 17548) // 50% larger than VALUE_KNOWN_WIN, but smaller than TB wins. + && eval < 22266) // larger than VALUE_KNOWN_WIN, but smaller than TB wins. return eval; // Step 9. Null move search with verification search (~22 Elo) if ( !PvNode && (ss-1)->currentMove != MOVE_NULL - && (ss-1)->statScore < 13706 + && (ss-1)->statScore < 15075 && eval >= beta && eval >= ss->staticEval - && ss->staticEval >= beta - 19 * depth - improvement / 15 + 200 + complexity / 25 + && ss->staticEval >= beta - 18 * depth - improvement / 19 + 215 + complexity / 30 && !excludedMove && pos.non_pawn_material(us) && (ss->ply >= thisThread->nmpMinPly || us != thisThread->nmpColor)) @@ -808,7 +808,7 @@ namespace { assert(eval - beta >= 0); // Null move dynamic reduction based on depth, eval and complexity of position - Depth R = std::min(int(eval - beta) / 205, 3) + depth / 3 + 4 - (complexity > 500); + Depth R = std::min(int(eval - beta) / 184, 4) + depth / 3 + 4 - (complexity > 799); ss->currentMove = MOVE_NULL; ss->continuationHistory = &thisThread->continuationHistory[0][0][NO_PIECE][0]; @@ -844,13 +844,13 @@ namespace { } } - probCutBeta = beta + 229 - 47 * improving; + probCutBeta = beta + 204 - 52 * improving; // Step 10. ProbCut (~4 Elo) // If we have a good enough capture and a reduced search returns a value // much above beta, we can (almost) safely prune the previous move. if ( !PvNode - && depth > 3 + && depth > 4 && abs(beta) < VALUE_TB_WIN_IN_MAX_PLY // if value from transposition table is lower than probCutBeta, don't attempt probCut // there and in further interactions with transposition table cutoff depth is set to depth - 3 @@ -908,12 +908,12 @@ namespace { // Step 11. If the position is not in TT, decrease depth by 2 or 1 depending on node type (~3 Elo) if ( PvNode - && depth >= 4 + && depth >= 3 && !ttMove) depth -= 2; if ( cutNode - && depth >= 7 + && depth >= 8 && !ttMove) depth--; @@ -923,7 +923,7 @@ moves_loop: // When in check, search starts here probCutBeta = beta + 401; if ( ss->inCheck && !PvNode - && depth >= 4 + && depth >= 2 && ttCapture && (tte->bound() & BOUND_LOWER) && tte->depth() >= depth - 3 @@ -1014,14 +1014,14 @@ moves_loop: // When in check, search starts here if ( !pos.empty(to_sq(move)) && !givesCheck && !PvNode - && lmrDepth < 6 + && lmrDepth < 7 && !ss->inCheck - && ss->staticEval + 392 + 207 * lmrDepth + PieceValue[EG][pos.piece_on(to_sq(move))] - + captureHistory[movedPiece][to_sq(move)][type_of(pos.piece_on(to_sq(move)))] / 8 < alpha) + && ss->staticEval + 424 + 138 * lmrDepth + PieceValue[EG][pos.piece_on(to_sq(move))] + + captureHistory[movedPiece][to_sq(move)][type_of(pos.piece_on(to_sq(move)))] / 7 < alpha) continue; // SEE based pruning (~9 Elo) - if (!pos.see_ge(move, Value(-200) * depth)) + if (!pos.see_ge(move, Value(-214) * depth)) continue; } else @@ -1040,11 +1040,11 @@ moves_loop: // When in check, search starts here // Futility pruning: parent node (~9 Elo) if ( !ss->inCheck && lmrDepth < 11 - && ss->staticEval + 131 + 137 * lmrDepth + history / 64 <= alpha) + && ss->staticEval + 147 + 125 * lmrDepth + history / 64 <= alpha) continue; // Prune moves with negative SEE (~3 Elo) - if (!pos.see_ge(move, Value(-25 * lmrDepth * lmrDepth - 29 * lmrDepth))) + if (!pos.see_ge(move, Value(-23 * lmrDepth * lmrDepth - 31 * lmrDepth))) continue; } } @@ -1067,7 +1067,7 @@ moves_loop: // When in check, search starts here && (tte->bound() & BOUND_LOWER) && tte->depth() >= depth - 3) { - Value singularBeta = ttValue - 3 * depth; + Value singularBeta = ttValue - 4 * depth; Depth singularDepth = (depth - 1) / 2; ss->excludedMove = move; @@ -1080,8 +1080,8 @@ moves_loop: // When in check, search starts here // Avoid search explosion by limiting the number of double extensions if ( !PvNode - && value < singularBeta - 71 - && ss->doubleExtensions <= 6) + && value < singularBeta - 52 + && ss->doubleExtensions <= 8) extension = 2; } @@ -1100,15 +1100,15 @@ moves_loop: // When in check, search starts here // Check extensions (~1 Elo) else if ( givesCheck - && depth > 7 - && abs(ss->staticEval) > 128) + && depth > 8 + && abs(ss->staticEval) > 81) extension = 1; // Quiet ttMove extensions (~0 Elo) else if ( PvNode && move == ttMove && move == ss->killers[0] - && (*contHist[0])[movedPiece][to_sq(move)] >= 8932) + && (*contHist[0])[movedPiece][to_sq(move)] >= 7546) extension = 1; } @@ -1145,7 +1145,7 @@ moves_loop: // When in check, search starts here // Decrease reduction at some PvNodes (~2 Elo) if ( PvNode - && bestMoveCount <= 4) + && bestMoveCount <= 3) r--; // Decrease reduction if position is or has been on the PV @@ -1170,18 +1170,18 @@ moves_loop: // When in check, search starts here + (*contHist[0])[movedPiece][to_sq(move)] + (*contHist[1])[movedPiece][to_sq(move)] + (*contHist[3])[movedPiece][to_sq(move)] - - 4142; + - 4123; // Decrease/increase reduction for moves with a good/bad history (~30 Elo) - r -= ss->statScore / 15328; + r -= ss->statScore / 17417; // In general we want to cap the LMR depth search at newDepth. But if reductions // are really negative and movecount is low, we allow this move to be searched // deeper than the first move (this may lead to hidden double extensions). int deeper = r >= -1 ? 0 : moveCount <= 5 ? 2 - : PvNode && depth > 4 ? 1 - : cutNode && moveCount <= 5 ? 1 + : PvNode && depth > 3 ? 1 + : cutNode && moveCount <= 7 ? 1 : 0; Depth d = std::clamp(newDepth - r, 1, newDepth + deeper); @@ -1190,7 +1190,7 @@ moves_loop: // When in check, search starts here // If the son is reduced and fails high it will be re-searched at full depth doFullDepthSearch = value > alpha && d < newDepth; - doDeeperSearch = value > (alpha + 80 + 20 * (newDepth - d)); + doDeeperSearch = value > (alpha + 76 + 11 * (newDepth - d)); didLMR = true; } else @@ -1211,7 +1211,7 @@ moves_loop: // When in check, search starts here : -stat_bonus(newDepth); if (captureOrPromotion) - bonus /= 5; + bonus /= 6; update_continuation_histories(ss, movedPiece, to_sq(move), bonus); } @@ -1335,14 +1335,14 @@ moves_loop: // When in check, search starts here quietsSearched, quietCount, capturesSearched, captureCount, depth); // Bonus for prior countermove that caused the fail low - else if ( (depth >= 3 || PvNode) + else if ( (depth >= 4 || PvNode) && !priorCapture) { //Assign extra bonus if current node is PvNode or cutNode //or fail low was really bad bool extraBonus = PvNode || cutNode - || bestValue < alpha - 99 * depth; + || bestValue < alpha - 71 * depth; update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, stat_bonus(depth) * (1 + extraBonus)); } @@ -1473,7 +1473,7 @@ moves_loop: // When in check, search starts here if (PvNode && bestValue > alpha) alpha = bestValue; - futilityBase = bestValue + 127; + futilityBase = bestValue + 139; } const PieceToHistory* contHist[] = { (ss-1)->continuationHistory, (ss-2)->continuationHistory, From 84b1940fcae95bb0a641dda9e85cb96f8c21cd22 Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Thu, 17 Feb 2022 10:54:07 +0300 Subject: [PATCH 088/105] Tune search at very long time control This patch is a result of tuning done by user @candirufish after 150k games. Since the tuned values were really interesting and touched heuristics that are known for their non-linear scaling I decided to run limited games LTC match, even if the STC test was really bad (which was expected). After seeing the results of the LTC match, I also run a VLTC (very long time control) SPRTtest, which passed. The main difference is in extensions: this patch allows much more singular/double extensions, both in terms of allowing them at lower depths and with lesser margins. Failed STC: https://tests.stockfishchess.org/tests/view/620d66643ec80158c0cd3b46 LLR: -2.94 (-2.94,2.94) <0.00,2.50> Total: 4968 W: 1194 L: 1398 D: 2376 Ptnml(0-2): 47, 633, 1294, 497, 13 Performed well at LTC in a fixed-length match: https://tests.stockfishchess.org/tests/view/620d66823ec80158c0cd3b4a ELO: 3.36 +-1.8 (95%) LOS: 100.0% Total: 30000 W: 7966 L: 7676 D: 14358 Ptnml(0-2): 36, 2936, 8755, 3248, 25 Passed VLTC SPRT test: https://tests.stockfishchess.org/tests/view/620da11a26f5b17ec884f939 LLR: 2.96 (-2.94,2.94) <0.50,3.00> Total: 4400 W: 1326 L: 1127 D: 1947 Ptnml(0-2): 13, 309, 1348, 526, 4 closes https://github.com/official-stockfish/Stockfish/pull/3937 Bench: 6318903 --- src/search.cpp | 88 +++++++++++++++++++++++++------------------------- 1 file changed, 44 insertions(+), 44 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 0b98bb27..e6420931 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -63,7 +63,7 @@ namespace { // Futility margin Value futility_margin(Depth d, bool improving) { - return Value(147 * (d - improving)); + return Value(168 * (d - improving)); } // Reductions lookup table, initialized at startup @@ -71,7 +71,7 @@ namespace { Depth reduction(bool i, Depth d, int mn, Value delta, Value rootDelta) { int r = Reductions[d] * Reductions[mn]; - return (r + 1627 - int(delta) * 1024 / int(rootDelta)) / 1024 + (!i && r > 992); + return (r + 1463 - int(delta) * 1024 / int(rootDelta)) / 1024 + (!i && r > 1010); } constexpr int futility_move_count(bool improving, Depth depth) { @@ -80,7 +80,7 @@ namespace { // History and stats update bonus, based on depth int stat_bonus(Depth d) { - return std::min((8 * d + 281) * d - 241 , 1949); + return std::min((9 * d + 270) * d - 311 , 2145); } // Add a small random component to draw evaluations to avoid 3-fold blindness @@ -157,7 +157,7 @@ namespace { void Search::init() { for (int i = 1; i < MAX_MOVES; ++i) - Reductions[i] = int((21.14 + std::log(Threads.size()) / 2) * std::log(i)); + Reductions[i] = int((20.81 + std::log(Threads.size()) / 2) * std::log(i)); } @@ -303,10 +303,10 @@ void Thread::search() { multiPV = std::min(multiPV, rootMoves.size()); - complexityAverage.set(211, 1); + complexityAverage.set(202, 1); trend = SCORE_ZERO; - optimism[ us] = Value(33); + optimism[ us] = Value(39); optimism[~us] = -optimism[us]; int searchAgainCounter = 0; @@ -349,16 +349,16 @@ void Thread::search() { if (rootDepth >= 4) { Value prev = rootMoves[pvIdx].averageScore; - delta = Value(19) + int(prev) * prev / 18321; + delta = Value(16) + int(prev) * prev / 19178; alpha = std::max(prev - delta,-VALUE_INFINITE); beta = std::min(prev + delta, VALUE_INFINITE); // Adjust trend and optimism based on root move's previousScore - int tr = sigmoid(prev, 4, 11, 92, 119, 1); + int tr = sigmoid(prev, 3, 8, 90, 125, 1); trend = (us == WHITE ? make_score(tr, tr / 2) : -make_score(tr, tr / 2)); - int opt = sigmoid(prev, 9, 18, 115, 12250, 187); + int opt = sigmoid(prev, 8, 17, 144, 13966, 183); optimism[ us] = Value(opt); optimism[~us] = -optimism[us]; } @@ -459,17 +459,17 @@ void Thread::search() { && !Threads.stop && !mainThread->stopOnPonderhit) { - double fallingEval = (66 + 12 * (mainThread->bestPreviousAverageScore - bestValue) - + 6 * (mainThread->iterValue[iterIdx] - bestValue)) / 809.70; + double fallingEval = (69 + 12 * (mainThread->bestPreviousAverageScore - bestValue) + + 6 * (mainThread->iterValue[iterIdx] - bestValue)) / 781.4; fallingEval = std::clamp(fallingEval, 0.5, 1.5); // If the bestMove is stable over several iterations, reduce time accordingly - timeReduction = lastBestMoveDepth + 8 < completedDepth ? 1.73 : 0.94; - double reduction = (1.66 + mainThread->previousTimeReduction) / (2.35 * timeReduction); + timeReduction = lastBestMoveDepth + 10 < completedDepth ? 1.63 : 0.73; + double reduction = (1.56 + mainThread->previousTimeReduction) / (2.20 * timeReduction); double bestMoveInstability = 1.073 + std::max(1.0, 2.25 - 9.9 / rootDepth) * totBestMoveChanges / Threads.size(); int complexity = mainThread->complexityAverage.value(); - double complexPosition = std::clamp(1.0 + (complexity - 293) / 1525.0, 0.5, 1.5); + double complexPosition = std::clamp(1.0 + (complexity - 326) / 1618.1, 0.5, 1.5); double totalTime = Time.optimum() * fallingEval * reduction * bestMoveInstability * complexPosition; @@ -490,7 +490,7 @@ void Thread::search() { } else if ( Threads.increaseDepth && !mainThread->ponder - && Time.elapsed() > totalTime * 0.49) + && Time.elapsed() > totalTime * 0.43) Threads.increaseDepth = false; else Threads.increaseDepth = true; @@ -766,7 +766,7 @@ namespace { // margin and the improving flag are used in various pruning heuristics. improvement = (ss-2)->staticEval != VALUE_NONE ? ss->staticEval - (ss-2)->staticEval : (ss-4)->staticEval != VALUE_NONE ? ss->staticEval - (ss-4)->staticEval - : 184; + : 175; improving = improvement > 0; complexity = abs(ss->staticEval - (us == WHITE ? eg_value(pos.psq_score()) : -eg_value(pos.psq_score()))); @@ -777,8 +777,8 @@ namespace { // If eval is really low check with qsearch if it can exceed alpha, if it can't, // return a fail low. if ( !PvNode - && depth <= 6 - && eval < alpha - 486 - 314 * depth * depth) + && depth <= 7 + && eval < alpha - 348 - 258 * depth * depth) { value = qsearch(pos, ss, alpha - 1, alpha); if (value < alpha) @@ -791,16 +791,16 @@ namespace { && depth < 8 && eval - futility_margin(depth, improving) - (ss-1)->statScore / 256 >= beta && eval >= beta - && eval < 22266) // larger than VALUE_KNOWN_WIN, but smaller than TB wins. + && eval < 26305) // larger than VALUE_KNOWN_WIN, but smaller than TB wins. return eval; // Step 9. Null move search with verification search (~22 Elo) if ( !PvNode && (ss-1)->currentMove != MOVE_NULL - && (ss-1)->statScore < 15075 + && (ss-1)->statScore < 14695 && eval >= beta && eval >= ss->staticEval - && ss->staticEval >= beta - 18 * depth - improvement / 19 + 215 + complexity / 30 + && ss->staticEval >= beta - 15 * depth - improvement / 15 + 198 + complexity / 28 && !excludedMove && pos.non_pawn_material(us) && (ss->ply >= thisThread->nmpMinPly || us != thisThread->nmpColor)) @@ -808,7 +808,7 @@ namespace { assert(eval - beta >= 0); // Null move dynamic reduction based on depth, eval and complexity of position - Depth R = std::min(int(eval - beta) / 184, 4) + depth / 3 + 4 - (complexity > 799); + Depth R = std::min(int(eval - beta) / 147, 5) + depth / 3 + 4 - (complexity > 753); ss->currentMove = MOVE_NULL; ss->continuationHistory = &thisThread->continuationHistory[0][0][NO_PIECE][0]; @@ -844,7 +844,7 @@ namespace { } } - probCutBeta = beta + 204 - 52 * improving; + probCutBeta = beta + 179 - 46 * improving; // Step 10. ProbCut (~4 Elo) // If we have a good enough capture and a reduced search returns a value @@ -920,7 +920,7 @@ namespace { moves_loop: // When in check, search starts here // Step 12. A small Probcut idea, when we are in check (~0 Elo) - probCutBeta = beta + 401; + probCutBeta = beta + 481; if ( ss->inCheck && !PvNode && depth >= 2 @@ -1014,14 +1014,14 @@ moves_loop: // When in check, search starts here if ( !pos.empty(to_sq(move)) && !givesCheck && !PvNode - && lmrDepth < 7 + && lmrDepth < 6 && !ss->inCheck - && ss->staticEval + 424 + 138 * lmrDepth + PieceValue[EG][pos.piece_on(to_sq(move))] - + captureHistory[movedPiece][to_sq(move)][type_of(pos.piece_on(to_sq(move)))] / 7 < alpha) + && ss->staticEval + 281 + 179 * lmrDepth + PieceValue[EG][pos.piece_on(to_sq(move))] + + captureHistory[movedPiece][to_sq(move)][type_of(pos.piece_on(to_sq(move)))] / 6 < alpha) continue; // SEE based pruning (~9 Elo) - if (!pos.see_ge(move, Value(-214) * depth)) + if (!pos.see_ge(move, Value(-203) * depth)) continue; } else @@ -1040,11 +1040,11 @@ moves_loop: // When in check, search starts here // Futility pruning: parent node (~9 Elo) if ( !ss->inCheck && lmrDepth < 11 - && ss->staticEval + 147 + 125 * lmrDepth + history / 64 <= alpha) + && ss->staticEval + 122 + 138 * lmrDepth + history / 60 <= alpha) continue; // Prune moves with negative SEE (~3 Elo) - if (!pos.see_ge(move, Value(-23 * lmrDepth * lmrDepth - 31 * lmrDepth))) + if (!pos.see_ge(move, Value(-25 * lmrDepth * lmrDepth - 20 * lmrDepth))) continue; } } @@ -1059,7 +1059,7 @@ moves_loop: // When in check, search starts here // a reduced search on all the other moves but the ttMove and if the // result is lower than ttValue minus a margin, then we will extend the ttMove. if ( !rootNode - && depth >= 6 + 2 * (PvNode && tte->is_pv()) + && depth >= 4 + 2 * (PvNode && tte->is_pv()) && move == ttMove && !excludedMove // Avoid recursive singular search /* && ttValue != VALUE_NONE Already implicit in the next condition */ @@ -1067,7 +1067,7 @@ moves_loop: // When in check, search starts here && (tte->bound() & BOUND_LOWER) && tte->depth() >= depth - 3) { - Value singularBeta = ttValue - 4 * depth; + Value singularBeta = ttValue - 3 * depth; Depth singularDepth = (depth - 1) / 2; ss->excludedMove = move; @@ -1080,7 +1080,7 @@ moves_loop: // When in check, search starts here // Avoid search explosion by limiting the number of double extensions if ( !PvNode - && value < singularBeta - 52 + && value < singularBeta - 26 && ss->doubleExtensions <= 8) extension = 2; } @@ -1100,15 +1100,15 @@ moves_loop: // When in check, search starts here // Check extensions (~1 Elo) else if ( givesCheck - && depth > 8 - && abs(ss->staticEval) > 81) + && depth > 9 + && abs(ss->staticEval) > 71) extension = 1; // Quiet ttMove extensions (~0 Elo) else if ( PvNode && move == ttMove && move == ss->killers[0] - && (*contHist[0])[movedPiece][to_sq(move)] >= 7546) + && (*contHist[0])[movedPiece][to_sq(move)] >= 5491) extension = 1; } @@ -1170,18 +1170,18 @@ moves_loop: // When in check, search starts here + (*contHist[0])[movedPiece][to_sq(move)] + (*contHist[1])[movedPiece][to_sq(move)] + (*contHist[3])[movedPiece][to_sq(move)] - - 4123; + - 4334; // Decrease/increase reduction for moves with a good/bad history (~30 Elo) - r -= ss->statScore / 17417; + r -= ss->statScore / 15914; // In general we want to cap the LMR depth search at newDepth. But if reductions // are really negative and movecount is low, we allow this move to be searched // deeper than the first move (this may lead to hidden double extensions). int deeper = r >= -1 ? 0 - : moveCount <= 5 ? 2 - : PvNode && depth > 3 ? 1 - : cutNode && moveCount <= 7 ? 1 + : moveCount <= 4 ? 2 + : PvNode && depth > 4 ? 1 + : cutNode && moveCount <= 8 ? 1 : 0; Depth d = std::clamp(newDepth - r, 1, newDepth + deeper); @@ -1190,7 +1190,7 @@ moves_loop: // When in check, search starts here // If the son is reduced and fails high it will be re-searched at full depth doFullDepthSearch = value > alpha && d < newDepth; - doDeeperSearch = value > (alpha + 76 + 11 * (newDepth - d)); + doDeeperSearch = value > (alpha + 78 + 11 * (newDepth - d)); didLMR = true; } else @@ -1342,7 +1342,7 @@ moves_loop: // When in check, search starts here //or fail low was really bad bool extraBonus = PvNode || cutNode - || bestValue < alpha - 71 * depth; + || bestValue < alpha - 70 * depth; update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, stat_bonus(depth) * (1 + extraBonus)); } @@ -1473,7 +1473,7 @@ moves_loop: // When in check, search starts here if (PvNode && bestValue > alpha) alpha = bestValue; - futilityBase = bestValue + 139; + futilityBase = bestValue + 118; } const PieceToHistory* contHist[] = { (ss-1)->continuationHistory, (ss-2)->continuationHistory, From 2da1d1bf571e3fd2e1d6cf56b76a7504de1a9453 Mon Sep 17 00:00:00 2001 From: ppigazzini Date: Sun, 6 Feb 2022 19:20:30 +0100 Subject: [PATCH 089/105] Add ARM NDK to Github Actions matrix - set the variable only for the required tests to keep simple the yml file - use NDK 21.x until will be fixed the Stockfish static build problem with NDK 23.x - set the test for armv7, armv7-neon, armv8 builds: - use armv7a-linux-androideabi21-clang++ compiler for armv7 armv7-neon - enforce a static build - silence the Warning for the unused compilation flag "-pie" with the static build, otherwise the Github workflow stops - use qemu to bench the build and get the signature Many thanks to @pschneider1968 that made all the hard work with NDK :) closes https://github.com/official-stockfish/Stockfish/pull/3924 No functional change --- .github/workflows/stockfish.yml | 68 +++++++++++++++++++++++++++------ 1 file changed, 56 insertions(+), 12 deletions(-) diff --git a/.github/workflows/stockfish.yml b/.github/workflows/stockfish.yml index 33126a11..f1741ed8 100644 --- a/.github/workflows/stockfish.yml +++ b/.github/workflows/stockfish.yml @@ -5,6 +5,7 @@ on: - master - tools - github_ci + - github_ci_armv7 pull_request: branches: - master @@ -20,6 +21,12 @@ jobs: strategy: matrix: config: + # set the variable for the required tests: + # run_expensive_tests: true + # run_32bit_tests: true + # run_64bit_tests: true + # run_armv8_tests: true + # run_armv7_tests: true - { name: "Ubuntu 20.04 GCC", os: ubuntu-20.04, @@ -35,18 +42,31 @@ jobs: os: ubuntu-20.04, compiler: clang++, comp: clang, - run_expensive_tests: false, run_32bit_tests: true, run_64bit_tests: true, shell: 'bash {0}' } + - { + name: "Ubuntu 20.04 NDK armv8", + os: ubuntu-20.04, + compiler: aarch64-linux-android21-clang++, + comp: ndk, + run_armv8_tests: true, + shell: 'bash {0}' + } + - { + name: "Ubuntu 20.04 NDK armv7", + os: ubuntu-20.04, + compiler: armv7a-linux-androideabi21-clang++, + comp: ndk, + run_armv7_tests: true, + shell: 'bash {0}' + } - { name: "MacOS 10.15 Apple Clang", os: macos-10.15, compiler: clang++, comp: clang, - run_expensive_tests: false, - run_32bit_tests: false, run_64bit_tests: true, shell: 'bash {0}' } @@ -55,8 +75,6 @@ jobs: os: macos-10.15, compiler: g++-10, comp: gcc, - run_expensive_tests: false, - run_32bit_tests: false, run_64bit_tests: true, shell: 'bash {0}' } @@ -65,8 +83,6 @@ jobs: os: windows-2022, compiler: g++, comp: gcc, - run_expensive_tests: false, - run_32bit_tests: false, run_64bit_tests: true, msys_sys: 'mingw64', msys_env: 'x86_64', @@ -77,9 +93,7 @@ jobs: os: windows-2022, compiler: g++, comp: gcc, - run_expensive_tests: false, run_32bit_tests: true, - run_64bit_tests: false, msys_sys: 'mingw32', msys_env: 'i686', shell: 'msys2 {0}' @@ -89,8 +103,6 @@ jobs: os: windows-2022, compiler: clang++, comp: clang, - run_expensive_tests: false, - run_32bit_tests: false, run_64bit_tests: true, msys_sys: 'clang64', msys_env: 'clang-x86_64', @@ -110,7 +122,7 @@ jobs: if: runner.os == 'Linux' run: | sudo apt update - sudo apt install expect valgrind g++-multilib + sudo apt install expect valgrind g++-multilib qemu-user - name: Setup msys and install required packages if: runner.os == 'Windows' @@ -130,6 +142,7 @@ jobs: - name: Check compiler run: | + export PATH=$PATH:$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin $COMPILER -v - name: Test help target @@ -251,6 +264,37 @@ jobs: make clean make -j2 ARCH=x86-64-vnni256 build + # armv8 tests + + - name: Test armv8 build + if: ${{ matrix.config.run_armv8_tests }} + run: | + export PATH=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH + export LDFLAGS="-static -Wno-unused-command-line-argument" + make clean + make -j2 ARCH=armv8 build + ../tests/signature.sh $benchref + + # armv7 tests + + - name: Test armv7 build + if: ${{ matrix.config.run_armv7_tests }} + run: | + export PATH=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH + export LDFLAGS="-static -Wno-unused-command-line-argument" + make clean + make -j2 ARCH=armv7 build + ../tests/signature.sh $benchref + + - name: Test armv7-neon build + if: ${{ matrix.config.run_armv7_tests }} + run: | + export PATH=$ANDROID_NDK_HOME/toolchains/llvm/prebuilt/linux-x86_64/bin:$PATH + export LDFLAGS="-static -Wno-unused-command-line-argument" + make clean + make -j2 ARCH=armv7-neon build + ../tests/signature.sh $benchref + # Other tests - name: Check perft and search reproducibility From abef3e86f42fd4953d28cc7c3381601475d11346 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Sun, 20 Feb 2022 17:36:19 +0100 Subject: [PATCH 090/105] Fix clang warning on unused variable mark variable as used. fixes https://github.com/official-stockfish/Stockfish/issues/3900 closes https://github.com/official-stockfish/Stockfish/pull/3941 No functional change --- src/evaluate.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index a5c049a8..923564cb 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -108,6 +108,7 @@ namespace Eval { MemoryBuffer buffer(const_cast(reinterpret_cast(gEmbeddedNNUEData)), size_t(gEmbeddedNNUESize)); + (void) gEmbeddedNNUEEnd; // Silence warning on unused variable istream stream(&buffer); if (load_eval(eval_file, stream)) From 27139dedac14af400f5b18e2ab50aca3f8cf0e33 Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Sat, 19 Feb 2022 18:24:11 +0300 Subject: [PATCH 091/105] Adjust usage of LMR for 2nd move in move ordering Current master prohibits usage of LMR for 2nd move at rootNode. This patch also disables LMR for 2nd move not only at rootNode but also at first PvNode that is a reply to rootNode. passed STC: https://tests.stockfishchess.org/tests/view/620e8c9026f5b17ec885143a LLR: 2.94 (-2.94,2.94) <0.00,2.50> Total: 54096 W: 14305 L: 13996 D: 25795 Ptnml(0-2): 209, 6075, 14192, 6342, 230 passed LTC: https://tests.stockfishchess.org/tests/view/620eb327b1792e8985f81fb8 LLR: 2.94 (-2.94,2.94) <0.50,3.00> Total: 110864 W: 29602 L: 29156 D: 52106 Ptnml(0-2): 112, 11147, 32455, 11619, 99 closes https://github.com/official-stockfish/Stockfish/pull/3940 bench 6820724 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index e6420931..6785ba4c 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1136,7 +1136,7 @@ moves_loop: // When in check, search starts here // been searched. In general we would like to reduce them, but there are many // cases where we extend a son if it has good chances to be "interesting". if ( depth >= 2 - && moveCount > 1 + rootNode + && moveCount > 1 + (PvNode && ss->ply <= 1) && ( !ss->ttPv || !captureOrPromotion || (cutNode && (ss-1)->moveCount > 1))) From 5f781d366e0f4369ec12e36c9978ad63ffa32235 Mon Sep 17 00:00:00 2001 From: mstembera Date: Wed, 23 Feb 2022 18:19:36 -0800 Subject: [PATCH 092/105] Clean up and simplify some nnue code. Remove some unnecessary code and it's execution during inference. Also the change on line 49 in nnue_architecture.h results in a more efficient SIMD code path through ClippedReLU::propagate(). passed STC: https://tests.stockfishchess.org/tests/view/6217d3bfda649bba32ef25d5 LLR: 2.94 (-2.94,2.94) <-2.25,0.25> Total: 12056 W: 3281 L: 3092 D: 5683 Ptnml(0-2): 55, 1213, 3312, 1384, 64 passed STC SMP: https://tests.stockfishchess.org/tests/view/6217f344da649bba32ef295e LLR: 2.94 (-2.94,2.94) <-2.25,0.25> Total: 27376 W: 7295 L: 7137 D: 12944 Ptnml(0-2): 52, 2859, 7715, 3003, 59 closes https://github.com/official-stockfish/Stockfish/pull/3944 No functional change bench: 6820724 --- src/nnue/evaluate_nnue.cpp | 6 +++--- src/nnue/layers/affine_transform.h | 16 ++++++++-------- src/nnue/layers/clipped_relu.h | 8 -------- src/nnue/nnue_architecture.h | 19 ++++++++++--------- src/nnue/nnue_common.h | 4 ++-- src/nnue/nnue_feature_transformer.h | 6 ++++-- 6 files changed, 27 insertions(+), 32 deletions(-) diff --git a/src/nnue/evaluate_nnue.cpp b/src/nnue/evaluate_nnue.cpp index 0fd58462..9254e36f 100644 --- a/src/nnue/evaluate_nnue.cpp +++ b/src/nnue/evaluate_nnue.cpp @@ -109,7 +109,7 @@ namespace Stockfish::Eval::NNUE { { write_little_endian(stream, Version); write_little_endian(stream, hashValue); - write_little_endian(stream, desc.size()); + write_little_endian(stream, (std::uint32_t)desc.size()); stream.write(&desc[0], desc.size()); return !stream.fail(); } @@ -157,7 +157,7 @@ namespace Stockfish::Eval::NNUE { ASSERT_ALIGNED(transformedFeatures, alignment); - const std::size_t bucket = (pos.count() - 1) / 4; + const int bucket = (pos.count() - 1) / 4; const auto psqt = featureTransformer->transform(pos, transformedFeatures, bucket); const auto positional = network[bucket]->propagate(transformedFeatures); @@ -197,7 +197,7 @@ namespace Stockfish::Eval::NNUE { NnueEvalTrace t{}; t.correctBucket = (pos.count() - 1) / 4; - for (std::size_t bucket = 0; bucket < LayerStacks; ++bucket) { + for (IndexType bucket = 0; bucket < LayerStacks; ++bucket) { const auto materialist = featureTransformer->transform(pos, transformedFeatures, bucket); const auto positional = network[bucket]->propagate(transformedFeatures); diff --git a/src/nnue/layers/affine_transform.h b/src/nnue/layers/affine_transform.h index 22451915..9a992608 100644 --- a/src/nnue/layers/affine_transform.h +++ b/src/nnue/layers/affine_transform.h @@ -235,10 +235,10 @@ namespace Stockfish::Eval::NNUE::Layers { // Read network parameters bool read_parameters(std::istream& stream) { - for (std::size_t i = 0; i < OutputDimensions; ++i) + for (IndexType i = 0; i < OutputDimensions; ++i) biases[i] = read_little_endian(stream); - for (std::size_t i = 0; i < OutputDimensions * PaddedInputDimensions; ++i) + for (IndexType i = 0; i < OutputDimensions * PaddedInputDimensions; ++i) weights[get_weight_index(i)] = read_little_endian(stream); return !stream.fail(); @@ -246,10 +246,10 @@ namespace Stockfish::Eval::NNUE::Layers { // Write network parameters bool write_parameters(std::ostream& stream) const { - for (std::size_t i = 0; i < OutputDimensions; ++i) + for (IndexType i = 0; i < OutputDimensions; ++i) write_little_endian(stream, biases[i]); - for (std::size_t i = 0; i < OutputDimensions * PaddedInputDimensions; ++i) + for (IndexType i = 0; i < OutputDimensions * PaddedInputDimensions; ++i) write_little_endian(stream, weights[get_weight_index(i)]); return !stream.fail(); @@ -422,9 +422,9 @@ namespace Stockfish::Eval::NNUE::Layers { // Read network parameters bool read_parameters(std::istream& stream) { - for (std::size_t i = 0; i < OutputDimensions; ++i) + for (IndexType i = 0; i < OutputDimensions; ++i) biases[i] = read_little_endian(stream); - for (std::size_t i = 0; i < OutputDimensions * PaddedInputDimensions; ++i) + for (IndexType i = 0; i < OutputDimensions * PaddedInputDimensions; ++i) weights[get_weight_index(i)] = read_little_endian(stream); return !stream.fail(); @@ -432,10 +432,10 @@ namespace Stockfish::Eval::NNUE::Layers { // Write network parameters bool write_parameters(std::ostream& stream) const { - for (std::size_t i = 0; i < OutputDimensions; ++i) + for (IndexType i = 0; i < OutputDimensions; ++i) write_little_endian(stream, biases[i]); - for (std::size_t i = 0; i < OutputDimensions * PaddedInputDimensions; ++i) + for (IndexType i = 0; i < OutputDimensions * PaddedInputDimensions; ++i) write_little_endian(stream, weights[get_weight_index(i)]); return !stream.fail(); diff --git a/src/nnue/layers/clipped_relu.h b/src/nnue/layers/clipped_relu.h index ffd2e3b7..f94d3082 100644 --- a/src/nnue/layers/clipped_relu.h +++ b/src/nnue/layers/clipped_relu.h @@ -171,14 +171,6 @@ namespace Stockfish::Eval::NNUE::Layers { std::max(0, std::min(127, input[i] >> WeightScaleBits))); } - // Affine transform layers expect that there is at least - // ceil_to_multiple(OutputDimensions, 32) initialized values. - // We cannot do this in the affine transform because it requires - // preallocating space here. - for (IndexType i = OutputDimensions; i < PaddedOutputDimensions; ++i) { - output[i] = 0; - } - return output; } }; diff --git a/src/nnue/nnue_architecture.h b/src/nnue/nnue_architecture.h index 725b40fb..b4f65364 100644 --- a/src/nnue/nnue_architecture.h +++ b/src/nnue/nnue_architecture.h @@ -46,7 +46,7 @@ struct Network static constexpr int FC_1_OUTPUTS = 32; Layers::AffineTransform fc_0; - Layers::ClippedReLU ac_0; + Layers::ClippedReLU ac_0; Layers::AffineTransform fc_1; Layers::ClippedReLU ac_1; Layers::AffineTransform fc_2; @@ -97,14 +97,19 @@ struct Network alignas(CacheLineSize) decltype(fc_1)::OutputBuffer fc_1_out; alignas(CacheLineSize) decltype(ac_1)::OutputBuffer ac_1_out; alignas(CacheLineSize) decltype(fc_2)::OutputBuffer fc_2_out; + + Buffer() + { + std::memset(this, 0, sizeof(*this)); + } }; #if defined(ALIGNAS_ON_STACK_VARIABLES_BROKEN) - char bufferRaw[sizeof(Buffer) + alignment]; - char* bufferRawAligned = align_ptr_up(&bufferRaw[0]); - Buffer& buffer = *(new (bufferRawAligned) Buffer); + static thread_local char bufferRaw[sizeof(Buffer) + alignment]; + static thread_local char* bufferRawAligned = align_ptr_up(&bufferRaw[0]); + static thread_local Buffer& buffer = *(new (bufferRawAligned) Buffer); #else - alignas(alignment) Buffer buffer; + alignas(alignment) static thread_local Buffer buffer; #endif fc_0.propagate(transformedFeatures, buffer.fc_0_out); @@ -118,10 +123,6 @@ struct Network std::int32_t fwdOut = int(buffer.fc_0_out[FC_0_OUTPUTS]) * (600*OutputScale) / (127*(1<>= 8; } } - u[i] = v; + u[i] = (std::uint8_t)v; stream.write(reinterpret_cast(u), sizeof(IntType)); } diff --git a/src/nnue/nnue_feature_transformer.h b/src/nnue/nnue_feature_transformer.h index fb867421..85598018 100644 --- a/src/nnue/nnue_feature_transformer.h +++ b/src/nnue/nnue_feature_transformer.h @@ -123,8 +123,10 @@ namespace Stockfish::Eval::NNUE { // We use __m* types as template arguments, which causes GCC to emit warnings // about losing some attribute information. This is irrelevant to us as we // only take their size, so the following pragma are harmless. + #if defined(__GNUC__) #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wignored-attributes" + #endif template (); static constexpr int NumPsqtRegs = BestRegisterCount(); - + #if defined(__GNUC__) #pragma GCC diagnostic pop - + #endif #endif From 174b038bf3b3b8a0d82422a861a050391a33f34a Mon Sep 17 00:00:00 2001 From: Tomasz Sobczyk Date: Sun, 27 Feb 2022 17:02:13 +0100 Subject: [PATCH 093/105] Use dynamic allocation for evaluation scratch TLS buffer. fixes #3946 an issue related with the toolchain as found in xcode 12 on macOS, related to previous commit 5f781d36. closes https://github.com/official-stockfish/Stockfish/pull/3950 No functional change --- src/nnue/nnue_architecture.h | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/src/nnue/nnue_architecture.h b/src/nnue/nnue_architecture.h index b4f65364..4f9596ae 100644 --- a/src/nnue/nnue_architecture.h +++ b/src/nnue/nnue_architecture.h @@ -21,6 +21,8 @@ #ifndef NNUE_ARCHITECTURE_H_INCLUDED #define NNUE_ARCHITECTURE_H_INCLUDED +#include + #include "nnue_common.h" #include "features/half_ka_v2_hm.h" @@ -88,9 +90,7 @@ struct Network std::int32_t propagate(const TransformedFeatureType* transformedFeatures) { - constexpr uint64_t alignment = CacheLineSize; - - struct Buffer + struct alignas(CacheLineSize) Buffer { alignas(CacheLineSize) decltype(fc_0)::OutputBuffer fc_0_out; alignas(CacheLineSize) decltype(ac_0)::OutputBuffer ac_0_out; @@ -104,12 +104,13 @@ struct Network } }; -#if defined(ALIGNAS_ON_STACK_VARIABLES_BROKEN) - static thread_local char bufferRaw[sizeof(Buffer) + alignment]; - static thread_local char* bufferRawAligned = align_ptr_up(&bufferRaw[0]); - static thread_local Buffer& buffer = *(new (bufferRawAligned) Buffer); +#if defined(__clang__) && (__APPLE__) + // workaround for a bug reported with xcode 12 + static thread_local auto tlsBuffer = std::make_unique(); + // Access TLS only once, cache result. + Buffer& buffer = *tlsBuffer; #else - alignas(alignment) static thread_local Buffer buffer; + alignas(CacheLineSize) static thread_local Buffer buffer; #endif fc_0.propagate(transformedFeatures, buffer.fc_0_out); From 4ac7d726ec5ba38ba593bca2ab5cb7589785a957 Mon Sep 17 00:00:00 2001 From: Giacomo Lorenzetti Date: Tue, 1 Mar 2022 09:34:40 +0100 Subject: [PATCH 094/105] Sort captures This patch (partially) sort captures in analogy to quiet moves. All three movepickers are affected, hence `depth` is added as an argument in probcut's. Passed STC: https://tests.stockfishchess.org/tests/view/621a4576da649bba32ef6fd4 LLR: 2.95 (-2.94,2.94) <0.00,2.50> Total: 103848 W: 27884 L: 27473 D: 48491 Ptnml(0-2): 587, 11691, 26974, 12068, 604 Passed LTC: https://tests.stockfishchess.org/tests/view/621aaa5bda649bba32ef7c2d LLR: 2.96 (-2.94,2.94) <0.50,3.00> Total: 212032 W: 56420 L: 55739 D: 99873 Ptnml(0-2): 198, 21310, 62348, 21933, 227 closes https://github.com/official-stockfish/Stockfish/pull/3952 Bench: 6833580 --- src/movepick.cpp | 11 ++++++----- src/movepick.h | 2 +- src/search.cpp | 2 +- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/src/movepick.cpp b/src/movepick.cpp index 694b9222..dc35113f 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -87,8 +87,8 @@ MovePicker::MovePicker(const Position& p, Move ttm, Depth d, const ButterflyHist /// MovePicker constructor for ProbCut: we generate captures with SEE greater /// than or equal to the given threshold. -MovePicker::MovePicker(const Position& p, Move ttm, Value th, const CapturePieceToHistory* cph) - : pos(p), captureHistory(cph), ttMove(ttm), threshold(th) +MovePicker::MovePicker(const Position& p, Move ttm, Value th, Depth d, const CapturePieceToHistory* cph) + : pos(p), captureHistory(cph), ttMove(ttm), threshold(th), depth(d) { assert(!pos.checkers()); @@ -169,11 +169,12 @@ top: endMoves = generate(pos, cur); score(); + partial_insertion_sort(cur, endMoves, -3000 * depth); ++stage; goto top; case GOOD_CAPTURE: - if (select([&](){ + if (select([&](){ return pos.see_ge(*cur, Value(-69 * cur->value / 1024)) ? // Move losing capture to endBadCaptures to be tried later true : (*endBadCaptures++ = *cur, false); })) @@ -241,10 +242,10 @@ top: return select([](){ return true; }); case PROBCUT: - return select([&](){ return pos.see_ge(*cur, threshold); }); + return select([&](){ return pos.see_ge(*cur, threshold); }); case QCAPTURE: - if (select([&](){ return depth > DEPTH_QS_RECAPTURES + if (select([&](){ return depth > DEPTH_QS_RECAPTURES || to_sq(*cur) == recaptureSquare; })) return *(cur - 1); diff --git a/src/movepick.h b/src/movepick.h index e2cbfcde..9a3c279b 100644 --- a/src/movepick.h +++ b/src/movepick.h @@ -126,7 +126,7 @@ public: const CapturePieceToHistory*, const PieceToHistory**, Square); - MovePicker(const Position&, Move, Value, const CapturePieceToHistory*); + MovePicker(const Position&, Move, Value, Depth, const CapturePieceToHistory*); Move next_move(bool skipQuiets = false); private: diff --git a/src/search.cpp b/src/search.cpp index 6785ba4c..a6552daf 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -863,7 +863,7 @@ namespace { { assert(probCutBeta < VALUE_INFINITE); - MovePicker mp(pos, ttMove, probCutBeta - ss->staticEval, &captureHistory); + MovePicker mp(pos, ttMove, probCutBeta - ss->staticEval, depth - 3, &captureHistory); bool ttPv = ss->ttPv; ss->ttPv = false; From 270a0e737fea1774b409f70f378ca52cbc42dd3d Mon Sep 17 00:00:00 2001 From: Ben Chaney Date: Tue, 1 Mar 2022 17:49:02 -0500 Subject: [PATCH 095/105] Generalize the feature transform to use vec_t macros This commit generalizes the feature transform to use vec_t macros that are architecture defined instead of using a seperate code path for each one. It should make some old architectures (MMX, including improvements by Fanael) faster and make further such improvements easier in the future. Includes some corrections to CI for mingw. closes https://github.com/official-stockfish/Stockfish/pull/3955 closes https://github.com/official-stockfish/Stockfish/pull/3928 No functional change --- .github/workflows/stockfish.yml | 12 +- AUTHORS | 1 + src/nnue/nnue_feature_transformer.h | 165 ++++++++++++---------------- 3 files changed, 78 insertions(+), 100 deletions(-) diff --git a/.github/workflows/stockfish.yml b/.github/workflows/stockfish.yml index f1741ed8..33560d52 100644 --- a/.github/workflows/stockfish.yml +++ b/.github/workflows/stockfish.yml @@ -82,20 +82,20 @@ jobs: name: "Windows 2022 Mingw-w64 GCC x86_64", os: windows-2022, compiler: g++, - comp: gcc, + comp: mingw, run_64bit_tests: true, msys_sys: 'mingw64', - msys_env: 'x86_64', + msys_env: 'x86_64-gcc', shell: 'msys2 {0}' } - { name: "Windows 2022 Mingw-w64 GCC i686", os: windows-2022, compiler: g++, - comp: gcc, + comp: mingw, run_32bit_tests: true, msys_sys: 'mingw32', - msys_env: 'i686', + msys_env: 'i686-gcc', shell: 'msys2 {0}' } - { @@ -105,7 +105,7 @@ jobs: comp: clang, run_64bit_tests: true, msys_sys: 'clang64', - msys_env: 'clang-x86_64', + msys_env: 'clang-x86_64-clang', shell: 'msys2 {0}' } @@ -129,7 +129,7 @@ jobs: uses: msys2/setup-msys2@v2 with: msystem: ${{matrix.config.msys_sys}} - install: mingw-w64-${{matrix.config.msys_env}}-${{matrix.config.comp}} make git expect + install: mingw-w64-${{matrix.config.msys_env}} make git expect - name: Download the used network from the fishtest framework run: | diff --git a/AUTHORS b/AUTHORS index f49c1db0..65620886 100644 --- a/AUTHORS +++ b/AUTHORS @@ -31,6 +31,7 @@ Arjun Temurnikar Artem Solopiy (EntityFX) Auguste Pop Balint Pfliegel +Ben Chaney (Chaneybenjamini) Ben Koshy (BKSpurgeon) Bill Henry (VoyagerOne) Bojun Guo (noobpwnftw, Nooby) diff --git a/src/nnue/nnue_feature_transformer.h b/src/nnue/nnue_feature_transformer.h index 85598018..c969ac6c 100644 --- a/src/nnue/nnue_feature_transformer.h +++ b/src/nnue/nnue_feature_transformer.h @@ -47,12 +47,22 @@ namespace Stockfish::Eval::NNUE { #define vec_store(a,b) _mm512_store_si512(a,b) #define vec_add_16(a,b) _mm512_add_epi16(a,b) #define vec_sub_16(a,b) _mm512_sub_epi16(a,b) + #define vec_mul_16(a,b) _mm512_mullo_epi16(a,b) + #define vec_zero() _mm512_setzero_epi32() + #define vec_set_16(a) _mm512_set1_epi16(a) + #define vec_max_16(a,b) _mm512_max_epi16(a,b) + #define vec_min_16(a,b) _mm512_min_epi16(a,b) + inline vec_t vec_msb_pack_16(vec_t a, vec_t b){ + vec_t compacted = _mm512_packs_epi16(_mm512_srli_epi16(a,7),_mm512_srli_epi16(b,7)); + return _mm512_permutexvar_epi64(_mm512_setr_epi64(0, 2, 4, 6, 1, 3, 5, 7), compacted); + } #define vec_load_psqt(a) _mm256_load_si256(a) #define vec_store_psqt(a,b) _mm256_store_si256(a,b) #define vec_add_psqt_32(a,b) _mm256_add_epi32(a,b) #define vec_sub_psqt_32(a,b) _mm256_sub_epi32(a,b) #define vec_zero_psqt() _mm256_setzero_si256() #define NumRegistersSIMD 32 + #define MaxChunkSize 64 #elif USE_AVX2 typedef __m256i vec_t; @@ -61,12 +71,22 @@ namespace Stockfish::Eval::NNUE { #define vec_store(a,b) _mm256_store_si256(a,b) #define vec_add_16(a,b) _mm256_add_epi16(a,b) #define vec_sub_16(a,b) _mm256_sub_epi16(a,b) + #define vec_mul_16(a,b) _mm256_mullo_epi16(a,b) + #define vec_zero() _mm256_setzero_si256() + #define vec_set_16(a) _mm256_set1_epi16(a) + #define vec_max_16(a,b) _mm256_max_epi16(a,b) + #define vec_min_16(a,b) _mm256_min_epi16(a,b) + inline vec_t vec_msb_pack_16(vec_t a, vec_t b){ + vec_t compacted = _mm256_packs_epi16(_mm256_srli_epi16(a,7), _mm256_srli_epi16(b,7)); + return _mm256_permute4x64_epi64(compacted, 0b11011000); + } #define vec_load_psqt(a) _mm256_load_si256(a) #define vec_store_psqt(a,b) _mm256_store_si256(a,b) #define vec_add_psqt_32(a,b) _mm256_add_epi32(a,b) #define vec_sub_psqt_32(a,b) _mm256_sub_epi32(a,b) #define vec_zero_psqt() _mm256_setzero_si256() #define NumRegistersSIMD 16 + #define MaxChunkSize 32 #elif USE_SSE2 typedef __m128i vec_t; @@ -75,12 +95,19 @@ namespace Stockfish::Eval::NNUE { #define vec_store(a,b) *(a)=(b) #define vec_add_16(a,b) _mm_add_epi16(a,b) #define vec_sub_16(a,b) _mm_sub_epi16(a,b) + #define vec_mul_16(a,b) _mm_mullo_epi16(a,b) + #define vec_zero() _mm_setzero_si128() + #define vec_set_16(a) _mm_set1_epi16(a) + #define vec_max_16(a,b) _mm_max_epi16(a,b) + #define vec_min_16(a,b) _mm_min_epi16(a,b) + #define vec_msb_pack_16(a,b) _mm_packs_epi16(_mm_srli_epi16(a,7),_mm_srli_epi16(b,7)) #define vec_load_psqt(a) (*(a)) #define vec_store_psqt(a,b) *(a)=(b) #define vec_add_psqt_32(a,b) _mm_add_epi32(a,b) #define vec_sub_psqt_32(a,b) _mm_sub_epi32(a,b) #define vec_zero_psqt() _mm_setzero_si128() #define NumRegistersSIMD (Is64Bit ? 16 : 8) + #define MaxChunkSize 16 #elif USE_MMX typedef __m64 vec_t; @@ -89,12 +116,26 @@ namespace Stockfish::Eval::NNUE { #define vec_store(a,b) *(a)=(b) #define vec_add_16(a,b) _mm_add_pi16(a,b) #define vec_sub_16(a,b) _mm_sub_pi16(a,b) + #define vec_mul_16(a,b) _mm_mullo_pi16(a,b) + #define vec_zero() _mm_setzero_si64() + #define vec_set_16(a) _mm_set1_pi16(a) + inline vec_t vec_max_16(vec_t a,vec_t b){ + vec_t comparison = _mm_cmpgt_pi16(a,b); + return _mm_or_si64(_mm_and_si64(comparison, a), _mm_andnot_si64(comparison, b)); + } + inline vec_t vec_min_16(vec_t a,vec_t b){ + vec_t comparison = _mm_cmpgt_pi16(a,b); + return _mm_or_si64(_mm_and_si64(comparison, b), _mm_andnot_si64(comparison, a)); + } + #define vec_msb_pack_16(a,b) _mm_packs_pi16(_mm_srli_pi16(a,7),_mm_srli_pi16(b,7)) #define vec_load_psqt(a) (*(a)) #define vec_store_psqt(a,b) *(a)=(b) #define vec_add_psqt_32(a,b) _mm_add_pi32(a,b) #define vec_sub_psqt_32(a,b) _mm_sub_pi32(a,b) #define vec_zero_psqt() _mm_setzero_si64() + #define vec_cleanup() _mm_empty() #define NumRegistersSIMD 8 + #define MaxChunkSize 8 #elif USE_NEON typedef int16x8_t vec_t; @@ -103,12 +144,24 @@ namespace Stockfish::Eval::NNUE { #define vec_store(a,b) *(a)=(b) #define vec_add_16(a,b) vaddq_s16(a,b) #define vec_sub_16(a,b) vsubq_s16(a,b) + #define vec_mul_16(a,b) vmulq_s16(a,b) + #define vec_zero() vec_t{0} + #define vec_set_16(a) vdupq_n_s16(a) + #define vec_max_16(a,b) vmaxq_s16(a,b) + #define vec_min_16(a,b) vminq_s16(a,b) + inline vec_t vec_msb_pack_16(vec_t a, vec_t b){ + const int8x8_t shifta = vshrn_n_s16(a, 7); + const int8x8_t shiftb = vshrn_n_s16(b, 7); + const int8x16_t compacted = vcombine_s8(shifta,shiftb); + return *reinterpret_cast (&compacted); + } #define vec_load_psqt(a) (*(a)) #define vec_store_psqt(a,b) *(a)=(b) #define vec_add_psqt_32(a,b) vaddq_s32(a,b) #define vec_sub_psqt_32(a,b) vsubq_s32(a,b) #define vec_zero_psqt() psqt_vec_t{0} #define NumRegistersSIMD 16 + #define MaxChunkSize 16 #else #undef VECTOR @@ -235,110 +288,30 @@ namespace Stockfish::Eval::NNUE { { const IndexType offset = (HalfDimensions / 2) * p; -#if defined(USE_AVX512) +#if defined(VECTOR) - constexpr IndexType OutputChunkSize = 512 / 8; + constexpr IndexType OutputChunkSize = MaxChunkSize; static_assert((HalfDimensions / 2) % OutputChunkSize == 0); constexpr IndexType NumOutputChunks = HalfDimensions / 2 / OutputChunkSize; - const __m512i Zero = _mm512_setzero_si512(); - const __m512i One = _mm512_set1_epi16(127); - const __m512i Control = _mm512_setr_epi64(0, 2, 4, 6, 1, 3, 5, 7); + vec_t Zero = vec_zero(); + vec_t One = vec_set_16(127); - const __m512i* in0 = reinterpret_cast(&(accumulation[perspectives[p]][0])); - const __m512i* in1 = reinterpret_cast(&(accumulation[perspectives[p]][HalfDimensions / 2])); - __m512i* out = reinterpret_cast< __m512i*>(output + offset); + const vec_t* in0 = reinterpret_cast(&(accumulation[perspectives[p]][0])); + const vec_t* in1 = reinterpret_cast(&(accumulation[perspectives[p]][HalfDimensions / 2])); + vec_t* out = reinterpret_cast< vec_t*>(output + offset); for (IndexType j = 0; j < NumOutputChunks; j += 1) { - const __m512i sum0a = _mm512_max_epi16(_mm512_min_epi16(in0[j * 2 + 0], One), Zero); - const __m512i sum0b = _mm512_max_epi16(_mm512_min_epi16(in0[j * 2 + 1], One), Zero); - const __m512i sum1a = _mm512_max_epi16(_mm512_min_epi16(in1[j * 2 + 0], One), Zero); - const __m512i sum1b = _mm512_max_epi16(_mm512_min_epi16(in1[j * 2 + 1], One), Zero); + const vec_t sum0a = vec_max_16(vec_min_16(in0[j * 2 + 0], One), Zero); + const vec_t sum0b = vec_max_16(vec_min_16(in0[j * 2 + 1], One), Zero); + const vec_t sum1a = vec_max_16(vec_min_16(in1[j * 2 + 0], One), Zero); + const vec_t sum1b = vec_max_16(vec_min_16(in1[j * 2 + 1], One), Zero); - const __m512i pa = _mm512_srli_epi16(_mm512_mullo_epi16(sum0a, sum1a), 7); - const __m512i pb = _mm512_srli_epi16(_mm512_mullo_epi16(sum0b, sum1b), 7); + const vec_t pa = vec_mul_16(sum0a, sum1a); + const vec_t pb = vec_mul_16(sum0b, sum1b); - out[j] = _mm512_permutexvar_epi64(Control, _mm512_packs_epi16(pa, pb)); - } - -#elif defined(USE_AVX2) - - constexpr IndexType OutputChunkSize = 256 / 8; - static_assert((HalfDimensions / 2) % OutputChunkSize == 0); - constexpr IndexType NumOutputChunks = HalfDimensions / 2 / OutputChunkSize; - - const __m256i Zero = _mm256_setzero_si256(); - const __m256i One = _mm256_set1_epi16(127); - constexpr int Control = 0b11011000; - - const __m256i* in0 = reinterpret_cast(&(accumulation[perspectives[p]][0])); - const __m256i* in1 = reinterpret_cast(&(accumulation[perspectives[p]][HalfDimensions / 2])); - __m256i* out = reinterpret_cast< __m256i*>(output + offset); - - for (IndexType j = 0; j < NumOutputChunks; j += 1) - { - const __m256i sum0a = _mm256_max_epi16(_mm256_min_epi16(in0[j * 2 + 0], One), Zero); - const __m256i sum0b = _mm256_max_epi16(_mm256_min_epi16(in0[j * 2 + 1], One), Zero); - const __m256i sum1a = _mm256_max_epi16(_mm256_min_epi16(in1[j * 2 + 0], One), Zero); - const __m256i sum1b = _mm256_max_epi16(_mm256_min_epi16(in1[j * 2 + 1], One), Zero); - - const __m256i pa = _mm256_srli_epi16(_mm256_mullo_epi16(sum0a, sum1a), 7); - const __m256i pb = _mm256_srli_epi16(_mm256_mullo_epi16(sum0b, sum1b), 7); - - out[j] = _mm256_permute4x64_epi64(_mm256_packs_epi16(pa, pb), Control); - } - -#elif defined(USE_SSE2) - - constexpr IndexType OutputChunkSize = 128 / 8; - static_assert((HalfDimensions / 2) % OutputChunkSize == 0); - constexpr IndexType NumOutputChunks = HalfDimensions / 2 / OutputChunkSize; - - const __m128i Zero = _mm_setzero_si128(); - const __m128i One = _mm_set1_epi16(127); - - const __m128i* in0 = reinterpret_cast(&(accumulation[perspectives[p]][0])); - const __m128i* in1 = reinterpret_cast(&(accumulation[perspectives[p]][HalfDimensions / 2])); - __m128i* out = reinterpret_cast< __m128i*>(output + offset); - - for (IndexType j = 0; j < NumOutputChunks; j += 1) - { - const __m128i sum0a = _mm_max_epi16(_mm_min_epi16(in0[j * 2 + 0], One), Zero); - const __m128i sum0b = _mm_max_epi16(_mm_min_epi16(in0[j * 2 + 1], One), Zero); - const __m128i sum1a = _mm_max_epi16(_mm_min_epi16(in1[j * 2 + 0], One), Zero); - const __m128i sum1b = _mm_max_epi16(_mm_min_epi16(in1[j * 2 + 1], One), Zero); - - const __m128i pa = _mm_srli_epi16(_mm_mullo_epi16(sum0a, sum1a), 7); - const __m128i pb = _mm_srli_epi16(_mm_mullo_epi16(sum0b, sum1b), 7); - - out[j] = _mm_packs_epi16(pa, pb); - } - -#elif defined(USE_NEON) - - constexpr IndexType OutputChunkSize = 128 / 8; - static_assert((HalfDimensions / 2) % OutputChunkSize == 0); - constexpr IndexType NumOutputChunks = HalfDimensions / 2 / OutputChunkSize; - - const int16x8_t Zero = vdupq_n_s16(0); - const int16x8_t One = vdupq_n_s16(127); - - const int16x8_t* in0 = reinterpret_cast(&(accumulation[perspectives[p]][0])); - const int16x8_t* in1 = reinterpret_cast(&(accumulation[perspectives[p]][HalfDimensions / 2])); - int8x16_t* out = reinterpret_cast< int8x16_t*>(output + offset); - - for (IndexType j = 0; j < NumOutputChunks; j += 1) - { - const int16x8_t sum0a = vmaxq_s16(vminq_s16(in0[j * 2 + 0], One), Zero); - const int16x8_t sum0b = vmaxq_s16(vminq_s16(in0[j * 2 + 1], One), Zero); - const int16x8_t sum1a = vmaxq_s16(vminq_s16(in1[j * 2 + 0], One), Zero); - const int16x8_t sum1b = vmaxq_s16(vminq_s16(in1[j * 2 + 1], One), Zero); - - const int8x8_t pa = vshrn_n_s16(vmulq_s16(sum0a, sum1a), 7); - const int8x8_t pb = vshrn_n_s16(vmulq_s16(sum0b, sum1b), 7); - - out[j] = vcombine_s8(pa, pb); + out[j] = vec_msb_pack_16(pa, pb); } #else @@ -354,6 +327,10 @@ namespace Stockfish::Eval::NNUE { #endif } +#if defined(vec_cleanup) + vec_cleanup(); +#endif + return psqt; } // end of function transform() From eae0f8dd066b31102b6663a60c36fffccf4e1269 Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Tue, 8 Mar 2022 10:56:07 +0300 Subject: [PATCH 096/105] Decrease reductions in Lmr for some Pv nodes This patch makes us reduce less in Lmr at pv nodes in case of static eval being far away from static evaluation of position. Idea is that if it's the case then probably position is pretty complex so we can't be sure about how reliable LMR is so we need to reduce less. Passed STC: https://tests.stockfishchess.org/tests/view/6226276aa9d47c8160e81220 LLR: 2.94 (-2.94,2.94) <0.00,2.50> Total: 262696 W: 69944 L: 69239 D: 123513 Ptnml(0-2): 1399, 29702, 68436, 30417, 1394 Passed LTC: https://tests.stockfishchess.org/tests/view/6226b002a9d47c8160e82b91 LLR: 2.95 (-2.94,2.94) <0.50,3.00> Total: 64008 W: 17320 L: 16982 D: 29706 Ptnml(0-2): 60, 6378, 18811, 6674, 81 closes https://github.com/official-stockfish/Stockfish/pull/3957 bench 6678390 --- src/search.cpp | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/search.cpp b/src/search.cpp index a6552daf..3008079e 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1166,6 +1166,11 @@ moves_loop: // When in check, search starts here if (ttCapture) r++; + // Decrease reduction at PvNodes if bestvalue + // is vastly different from static evaluation + if (PvNode && !ss->inCheck && abs(ss->staticEval - bestValue) > 250) + r--; + ss->statScore = thisThread->mainHistory[us][from_to(move)] + (*contHist[0])[movedPiece][to_sq(move)] + (*contHist[1])[movedPiece][to_sq(move)] From 45f2416db4eaba8fbf023f84609d68a60e94b4ff Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Wed, 9 Mar 2022 18:40:54 +0300 Subject: [PATCH 097/105] Improvements in Evaluation adjust parameters in classical evaluation and NNUE scaling. STC: LLR: 2.95 (-2.94,2.94) <0.00,2.50> Total: 37104 W: 9983 L: 9701 D: 17420 Ptnml(0-2): 154, 4187, 9651, 4343, 217 https://tests.stockfishchess.org/tests/view/6228cb13a9d47c8160e885ba LTC: LLR: 2.94 (-2.94,2.94) <0.50,3.00> Total: 266792 W: 71101 L: 70295 D: 125396 Ptnml(0-2): 214, 26928, 78353, 27640, 261 https://tests.stockfishchess.org/tests/view/6228d3c4a9d47c8160e887b0 closes https://github.com/official-stockfish/Stockfish/pull/3958 Bench: 6739741 --- src/evaluate.cpp | 44 ++++++++++++++++++++++---------------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 923564cb..e9376aa6 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -229,58 +229,58 @@ namespace { // BishopPawns[distance from edge] contains a file-dependent penalty for pawns on // squares of the same color as our bishop. constexpr Score BishopPawns[int(FILE_NB) / 2] = { - S(3, 8), S(3, 9), S(2, 8), S(3, 8) + S(3, 8), S(3, 9), S(2, 7), S(3, 7) }; // KingProtector[knight/bishop] contains penalty for each distance unit to own king - constexpr Score KingProtector[] = { S(8, 9), S(6, 9) }; + constexpr Score KingProtector[] = { S(9, 9), S(7, 9) }; // Outpost[knight/bishop] contains bonuses for each knight or bishop occupying a // pawn protected square on rank 4 to 6 which is also safe from a pawn attack. - constexpr Score Outpost[] = { S(57, 38), S(31, 24) }; + constexpr Score Outpost[] = { S(54, 34), S(31, 25) }; // PassedRank[Rank] contains a bonus according to the rank of a passed pawn constexpr Score PassedRank[RANK_NB] = { - S(0, 0), S(7, 27), S(16, 32), S(17, 40), S(64, 71), S(170, 174), S(278, 262) + S(0, 0), S(2, 38), S(15, 36), S(22, 50), S(64, 81), S(166, 184), S(284, 269) }; constexpr Score RookOnClosedFile = S(10, 5); - constexpr Score RookOnOpenFile[] = { S(19, 6), S(47, 26) }; + constexpr Score RookOnOpenFile[] = { S(18, 8), S(49, 26) }; // ThreatByMinor/ByRook[attacked PieceType] contains bonuses according to // which piece type attacks which one. Attacks on lesser pieces which are // pawn-defended are not considered. constexpr Score ThreatByMinor[PIECE_TYPE_NB] = { - S(0, 0), S(5, 32), S(55, 41), S(77, 56), S(89, 119), S(79, 162) + S(0, 0), S(6, 37), S(64, 50), S(82, 57), S(103, 130), S(81, 163) }; constexpr Score ThreatByRook[PIECE_TYPE_NB] = { - S(0, 0), S(3, 44), S(37, 68), S(42, 60), S(0, 39), S(58, 43) + S(0, 0), S(3, 44), S(36, 71), S(44, 59), S(0, 39), S(60, 39) }; constexpr Value CorneredBishop = Value(50); // Assorted bonuses and penalties - constexpr Score UncontestedOutpost = S( 1, 10); + constexpr Score UncontestedOutpost = S( 0, 10); constexpr Score BishopOnKingRing = S( 24, 0); constexpr Score BishopXRayPawns = S( 4, 5); constexpr Score FlankAttacks = S( 8, 0); - constexpr Score Hanging = S( 69, 36); + constexpr Score Hanging = S( 72, 40); constexpr Score KnightOnQueen = S( 16, 11); constexpr Score LongDiagonalBishop = S( 45, 0); constexpr Score MinorBehindPawn = S( 18, 3); - constexpr Score PassedFile = S( 11, 8); - constexpr Score PawnlessFlank = S( 17, 95); - constexpr Score ReachableOutpost = S( 31, 22); - constexpr Score RestrictedPiece = S( 7, 7); + constexpr Score PassedFile = S( 13, 8); + constexpr Score PawnlessFlank = S( 19, 97); + constexpr Score ReachableOutpost = S( 33, 19); + constexpr Score RestrictedPiece = S( 6, 7); constexpr Score RookOnKingRing = S( 16, 0); - constexpr Score SliderOnQueen = S( 60, 18); - constexpr Score ThreatByKing = S( 24, 89); + constexpr Score SliderOnQueen = S( 62, 21); + constexpr Score ThreatByKing = S( 24, 87); constexpr Score ThreatByPawnPush = S( 48, 39); - constexpr Score ThreatBySafePawn = S(173, 94); + constexpr Score ThreatBySafePawn = S(167, 99); constexpr Score TrappedRook = S( 55, 13); constexpr Score WeakQueenProtection = S( 14, 0); - constexpr Score WeakQueen = S( 56, 15); + constexpr Score WeakQueen = S( 57, 19); #undef S @@ -1088,23 +1088,23 @@ Value Eval::evaluate(const Position& pos) { // Deciding between classical and NNUE eval (~10 Elo): for high PSQ imbalance we use classical, // but we switch to NNUE during long shuffling or with high material on the board. if ( !useNNUE - || abs(eg_value(pos.psq_score())) * 5 > (849 + pos.non_pawn_material() / 64) * (5 + pos.rule50_count())) + || abs(eg_value(pos.psq_score())) * 5 > (856 + pos.non_pawn_material() / 64) * (5 + pos.rule50_count())) { v = Evaluation(pos).value(); // classical - useClassical = abs(v) >= 298; + useClassical = abs(v) >= 297; } // If result of a classical evaluation is much lower than threshold fall back to NNUE if (useNNUE && !useClassical) { Value nnue = NNUE::evaluate(pos, true); // NNUE - int scale = 1136 + 20 * pos.non_pawn_material() / 1024; + int scale = 1036 + 20 * pos.non_pawn_material() / 1024; Color stm = pos.side_to_move(); Value optimism = pos.this_thread()->optimism[stm]; Value psq = (stm == WHITE ? 1 : -1) * eg_value(pos.psq_score()); int complexity = 35 * abs(nnue - psq) / 256; - optimism = optimism * (44 + complexity) / 32; + optimism = optimism * (44 + complexity) / 31; v = (nnue + optimism) * scale / 1024 - optimism; if (pos.is_chess960()) @@ -1112,7 +1112,7 @@ Value Eval::evaluate(const Position& pos) { } // Damp down the evaluation linearly when shuffling - v = v * (208 - pos.rule50_count()) / 208; + v = v * (207 - pos.rule50_count()) / 207; // Guarantee evaluation does not hit the tablebase range v = std::clamp(v, VALUE_TB_LOSS_IN_MAX_PLY + 1, VALUE_TB_WIN_IN_MAX_PLY - 1); From 004ea2c25ebe2b900152d0d837089d03f20c8eca Mon Sep 17 00:00:00 2001 From: Giacomo Lorenzetti Date: Sat, 5 Feb 2022 10:18:50 +0100 Subject: [PATCH 098/105] Small cleanups Delete cast to int in movepick. update AUTHORS. adjust assert in sigmoid. fix spelling mistakes in README closes https://github.com/official-stockfish/Stockfish/pull/3922 closes https://github.com/official-stockfish/Stockfish/pull/3948 closes https://github.com/official-stockfish/Stockfish/pull/3942 No functional change --- AUTHORS | 1 + README.md | 19 +++++++++---------- src/misc.h | 2 +- src/movepick.cpp | 4 ++-- 4 files changed, 13 insertions(+), 13 deletions(-) diff --git a/AUTHORS b/AUTHORS index 65620886..34b95ba5 100644 --- a/AUTHORS +++ b/AUTHORS @@ -155,6 +155,7 @@ Pascal Romaret Pasquale Pigazzini (ppigazzini) Patrick Jansen (mibere) pellanda +Peter Schneider (pschneider1968) Peter Zsifkovits (CoffeeOne) Praveen Kumar Tummala (praveentml) Rahul Dsilva (silversolver1) diff --git a/README.md b/README.md index 330d19ed..37dae511 100644 --- a/README.md +++ b/README.md @@ -10,12 +10,11 @@ Cute Chess, eboard, Arena, Sigma Chess, Shredder, Chess Partner or Fritz) in ord to be used comfortably. Read the documentation for your GUI of choice for information about how to use Stockfish with it. -The Stockfish engine features two evaluation functions for chess, the classical -evaluation based on handcrafted terms, and the NNUE evaluation based on efficiently -updatable neural networks. The classical evaluation runs efficiently on almost all -CPU architectures, while the NNUE evaluation benefits from the vector -intrinsics available on most CPUs (sse2, avx2, neon, or similar). - +The Stockfish engine features two evaluation functions for chess. +The efficiently updatable neural network (NNUE) based evaluation is the default and by far the strongest. +The classical evaluation based on handcrafted terms remains available. +The strongest network is integrated in the binary and downloaded automatically during the build process. +The NNUE evaluation benefits from the vector intrinsics available on most CPUs (sse2, avx2, neon, or similar). ## Files @@ -37,7 +36,7 @@ This distribution of Stockfish consists of the following files: The Universal Chess Interface (UCI) is a standard protocol used to communicate with a chess engine, and is the recommended way to do so for typical graphical user interfaces -(GUI) or chess tools. Stockfish implements the majority of it options as described +(GUI) or chess tools. Stockfish implements the majority of its options as described in [the UCI protocol](https://www.shredderchess.com/download/div/uci.zip). Developers can see the default values for UCI options available in Stockfish by typing @@ -103,7 +102,7 @@ change them via a chess GUI. This is a list of available UCI options in Stockfis Example: `C:\tablebases\wdl345;C:\tablebases\wdl6;D:\tablebases\dtz345;D:\tablebases\dtz6` It is recommended to store .rtbw files on an SSD. There is no loss in storing - the .rtbz files on a regular HD. It is recommended to verify all md5 checksums + the .rtbz files on a regular HDD. It is recommended to verify all md5 checksums of the downloaded tablebase files (`md5sum -c checksum.md5`) as corruption will lead to engine crashes. @@ -322,10 +321,10 @@ it (either by itself or as part of some bigger software package), or using it as the starting point for a software project of your own. The only real limitation is that whenever you distribute Stockfish in -some way, you MUST always include the full source code, or a pointer +some way, you MUST always include the license, the full source code, or a pointer to where the source code can be found, to generate the exact binary you are distributing. If you make any changes to the source code, -these changes must also be made available under the GPL. +these changes must also be made available under the GPL v3. For full details, read the copy of the GPL v3 found in the file named [*Copying.txt*](https://github.com/official-stockfish/Stockfish/blob/master/Copying.txt). diff --git a/src/misc.h b/src/misc.h index b9626733..b666b6be 100644 --- a/src/misc.h +++ b/src/misc.h @@ -163,7 +163,7 @@ inline int64_t sigmoid(int64_t t, int64_t x0, int64_t P, int64_t Q) { - assert(C > 0); + assert(C > 0 && Q != 0); return y0 + P * (t-x0) / (Q * (std::abs(t-x0) + C)) ; } diff --git a/src/movepick.cpp b/src/movepick.cpp index dc35113f..c948620b 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -107,8 +107,8 @@ void MovePicker::score() { for (auto& m : *this) if constexpr (Type == CAPTURES) - m.value = int(PieceValue[MG][pos.piece_on(to_sq(m))]) * 6 - + (*captureHistory)[pos.moved_piece(m)][to_sq(m)][type_of(pos.piece_on(to_sq(m)))]; + m.value = 6 * PieceValue[MG][pos.piece_on(to_sq(m))] + + (*captureHistory)[pos.moved_piece(m)][to_sq(m)][type_of(pos.piece_on(to_sq(m)))]; else if constexpr (Type == QUIETS) m.value = (*mainHistory)[pos.side_to_move()][from_to(m)] From f3a2296e591d09dd50323fc3f96e800f5538d8bb Mon Sep 17 00:00:00 2001 From: mstembera Date: Sat, 12 Mar 2022 07:00:58 -0800 Subject: [PATCH 099/105] Small cleanups (2) - fix a small compile error under MSVC - improve sigmoid comment and assert - fix formatting in README.md closes https://github.com/official-stockfish/Stockfish/pull/3960 No functional change --- README.md | 71 ++++++++++++++++++++++++++---------------------- src/misc.h | 5 ++-- src/movepick.cpp | 4 +-- 3 files changed, 44 insertions(+), 36 deletions(-) diff --git a/README.md b/README.md index 37dae511..6e6e762e 100644 --- a/README.md +++ b/README.md @@ -10,23 +10,28 @@ Cute Chess, eboard, Arena, Sigma Chess, Shredder, Chess Partner or Fritz) in ord to be used comfortably. Read the documentation for your GUI of choice for information about how to use Stockfish with it. -The Stockfish engine features two evaluation functions for chess. -The efficiently updatable neural network (NNUE) based evaluation is the default and by far the strongest. -The classical evaluation based on handcrafted terms remains available. -The strongest network is integrated in the binary and downloaded automatically during the build process. -The NNUE evaluation benefits from the vector intrinsics available on most CPUs (sse2, avx2, neon, or similar). +The Stockfish engine features two evaluation functions for chess. The efficiently +updatable neural network (NNUE) based evaluation is the default and by far the strongest. +The classical evaluation based on handcrafted terms remains available. The strongest +network is integrated in the binary and downloaded automatically during the build process. +The NNUE evaluation benefits from the vector intrinsics available on most CPUs (sse2, +avx2, neon, or similar). ## Files This distribution of Stockfish consists of the following files: - * [Readme.md](https://github.com/official-stockfish/Stockfish/blob/master/README.md), the file you are currently reading. + * [Readme.md](https://github.com/official-stockfish/Stockfish/blob/master/README.md), + the file you are currently reading. - * [Copying.txt](https://github.com/official-stockfish/Stockfish/blob/master/Copying.txt), a text file containing the GNU General Public License version 3. + * [Copying.txt](https://github.com/official-stockfish/Stockfish/blob/master/Copying.txt), + a text file containing the GNU General Public License version 3. - * [AUTHORS](https://github.com/official-stockfish/Stockfish/blob/master/AUTHORS), a text file with the list of authors for the project + * [AUTHORS](https://github.com/official-stockfish/Stockfish/blob/master/AUTHORS), + a text file with the list of authors for the project - * [src](https://github.com/official-stockfish/Stockfish/tree/master/src), a subdirectory containing the full source code, including a Makefile + * [src](https://github.com/official-stockfish/Stockfish/tree/master/src), + a subdirectory containing the full source code, including a Makefile that can be used to compile Stockfish on Unix-like systems. * a file with the .nnue extension, storing the neural network for the NNUE @@ -67,9 +72,9 @@ change them via a chess GUI. This is a list of available UCI options in Stockfis * #### EvalFile The name of the file of the NNUE evaluation parameters. Depending on the GUI the - filename might have to include the full path to the folder/directory that contains the file. - Other locations, such as the directory that contains the binary and the working directory, - are also searched. + filename might have to include the full path to the folder/directory that contains + the file. Other locations, such as the directory that contains the binary and the + working directory, are also searched. * #### UCI_AnalyseMode An option handled by your GUI. @@ -137,8 +142,9 @@ change them via a chess GUI. This is a list of available UCI options in Stockfis For developers the following non-standard commands might be of interest, mainly useful for debugging: * #### bench *ttSize threads limit fenFile limitType evalType* - Performs a standard benchmark using various options. The signature of a version (standard node - count) is obtained using all defaults. `bench` is currently `bench 16 1 13 default depth mixed`. + Performs a standard benchmark using various options. The signature of a version + (standard node count) is obtained using all defaults. `bench` is currently + `bench 16 1 13 default depth mixed`. * #### compiler Give information about the compiler and environment used for building a binary. @@ -174,26 +180,27 @@ on the evaluations of millions of positions at moderate search depth. The NNUE evaluation was first introduced in shogi, and ported to Stockfish afterward. It can be evaluated efficiently on CPUs, and exploits the fact that only parts of the neural network need to be updated after a typical chess move. -[The nodchip repository](https://github.com/nodchip/Stockfish) provided the first version of -the needed tools to train and develop the NNUE networks. Today, more advanced training tools are available -in [the nnue-pytorch repository](https://github.com/glinscott/nnue-pytorch/), while data generation tools -are available in [a dedicated branch](https://github.com/official-stockfish/Stockfish/tree/tools). +[The nodchip repository](https://github.com/nodchip/Stockfish) provided the first +version of the needed tools to train and develop the NNUE networks. Today, more +advanced training tools are available in +[the nnue-pytorch repository](https://github.com/glinscott/nnue-pytorch/), +while data generation tools are available in +[a dedicated branch](https://github.com/official-stockfish/Stockfish/tree/tools). -On CPUs supporting modern vector instructions -(avx2 and similar), the NNUE evaluation results in much stronger playing strength, even -if the nodes per second computed by the engine is somewhat lower (roughly 80% of nps -is typical). +On CPUs supporting modern vector instructions (avx2 and similar), the NNUE evaluation +results in much stronger playing strength, even if the nodes per second computed by +the engine is somewhat lower (roughly 80% of nps is typical). Notes: -1) the NNUE evaluation depends on the Stockfish binary and the network parameter -file (see the EvalFile UCI option). Not every parameter file is compatible with a given -Stockfish binary, but the default value of the EvalFile UCI option is the name of a network -that is guaranteed to be compatible with that binary. +1) the NNUE evaluation depends on the Stockfish binary and the network parameter file +(see the EvalFile UCI option). Not every parameter file is compatible with a given +Stockfish binary, but the default value of the EvalFile UCI option is the name of a +network that is guaranteed to be compatible with that binary. 2) to use the NNUE evaluation, the additional data file with neural network parameters -needs to be available. Normally, this file is already embedded in the binary or it -can be downloaded. The filename for the default (recommended) net can be found as the default +needs to be available. Normally, this file is already embedded in the binary or it can +be downloaded. The filename for the default (recommended) net can be found as the default value of the `EvalFile` UCI option, with the format `nn-[SHA256 first 12 digits].nnue` (for instance, `nn-c157e0a5755b.nnue`). This file can be downloaded from ``` @@ -321,10 +328,10 @@ it (either by itself or as part of some bigger software package), or using it as the starting point for a software project of your own. The only real limitation is that whenever you distribute Stockfish in -some way, you MUST always include the license, the full source code, or a pointer -to where the source code can be found, to generate the exact binary -you are distributing. If you make any changes to the source code, -these changes must also be made available under the GPL v3. +some way, you MUST always include the license and the full source code +(or a pointer to where the source code can be found) to generate the +exact binary you are distributing. If you make any changes to the +source code, these changes must also be made available under the GPL v3. For full details, read the copy of the GPL v3 found in the file named [*Copying.txt*](https://github.com/official-stockfish/Stockfish/blob/master/Copying.txt). diff --git a/src/misc.h b/src/misc.h index b666b6be..dcef22a4 100644 --- a/src/misc.h +++ b/src/misc.h @@ -152,7 +152,7 @@ private: /// - the slope can be adjusted using C > 0, smaller C giving a steeper sigmoid /// - the slope of the sigmoid when t = x0 is P/(Q*C) /// - sigmoid is increasing with t when P > 0 and Q > 0 -/// - to get a decreasing sigmoid, call with -t, or change sign of P +/// - to get a decreasing sigmoid, change sign of P /// - mean value of the sigmoid is y0 /// /// Use to draw the sigmoid @@ -163,7 +163,8 @@ inline int64_t sigmoid(int64_t t, int64_t x0, int64_t P, int64_t Q) { - assert(C > 0 && Q != 0); + assert(C > 0); + assert(Q != 0); return y0 + P * (t-x0) / (Q * (std::abs(t-x0) + C)) ; } diff --git a/src/movepick.cpp b/src/movepick.cpp index c948620b..77453a45 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -107,8 +107,8 @@ void MovePicker::score() { for (auto& m : *this) if constexpr (Type == CAPTURES) - m.value = 6 * PieceValue[MG][pos.piece_on(to_sq(m))] - + (*captureHistory)[pos.moved_piece(m)][to_sq(m)][type_of(pos.piece_on(to_sq(m)))]; + m.value = 6 * int(PieceValue[MG][pos.piece_on(to_sq(m))]) + + (*captureHistory)[pos.moved_piece(m)][to_sq(m)][type_of(pos.piece_on(to_sq(m)))]; else if constexpr (Type == QUIETS) m.value = (*mainHistory)[pos.side_to_move()][from_to(m)] From e31f97e3baa52042fe60d6f4eeb50fe0d9e61013 Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Tue, 15 Mar 2022 16:53:59 +0100 Subject: [PATCH 100/105] Remove ttPv tree shrinking. Via the ttPv flag an implicit tree of current and former PV nodes is maintained. In addition this tree is grown or shrinked at the leafs dependant on the search results. But now the shrinking step has been removed. As the frequency of ttPv nodes decreases with depth the shown scaling behavior (STC barely passed but LTC scales well) of the tests was expected. STC: LLR: 2.93 (-2.94,2.94) <-2.25,0.25> Total: 270408 W: 71593 L: 71785 D: 127030 Ptnml(0-2): 1339, 31024, 70630, 30912, 1299 https://tests.stockfishchess.org/tests/view/622fbf9dc9e950cbfc2376d6 LTC: LLR: 2.96 (-2.94,2.94) <-2.25,0.25> Total: 34368 W: 9135 L: 8992 D: 16241 Ptnml(0-2): 28, 3423, 10135, 3574, 24 https://tests.stockfishchess.org/tests/view/62305257c9e950cbfc238964 closes https://github.com/official-stockfish/Stockfish/pull/3963 Bench: 7044203 --- src/search.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 3008079e..672abc05 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1359,10 +1359,6 @@ moves_loop: // When in check, search starts here // opponent move is probably good and the new position is added to the search tree. if (bestValue <= alpha) ss->ttPv = ss->ttPv || ((ss-1)->ttPv && depth > 3); - // Otherwise, a counter move has been found and if the position is the last leaf - // in the search tree, remove the position from the search tree. - else if (depth > 3) - ss->ttPv = ss->ttPv && (ss+1)->ttPv; // Write gathered information in transposition table if (!excludedMove && !(rootNode && thisThread->pvIdx)) From 910cf8b21839eb9f1991934a5436eea112021723 Mon Sep 17 00:00:00 2001 From: Giacomo Lorenzetti Date: Wed, 23 Mar 2022 12:04:10 +0100 Subject: [PATCH 101/105] Remove pos.capture_or_promotion() This patch replaces `pos.capture_or_promotion()` with `pos.capture()` and comes after a few attempts with elo-gaining bounds, two of which failed yellow at LTC (https://tests.stockfishchess.org/tests/view/622f8f0cc9e950cbfc237024 and https://tests.stockfishchess.org/tests/view/62319a8bb3b498ba71a6b2dc). Passed non-regression STC: https://tests.stockfishchess.org/tests/view/623aff7eea447151c74828d3 LLR: 2.94 (-2.94,2.94) <-2.25,0.25> Total: 246864 W: 65462 L: 65618 D: 115784 Ptnml(0-2): 1201, 28116, 65001, 27866, 1248 Passed non-regression LTC: https://tests.stockfishchess.org/tests/view/623c1fdcea447151c7484fb0 LLR: 2.94 (-2.94,2.94) <-2.25,0.25> Total: 30120 W: 8125 L: 7978 D: 14017 Ptnml(0-2): 22, 2993, 8881, 3144, 20 closes https://github.com/official-stockfish/Stockfish/pull/3968 Bench: 6847732 --- src/position.h | 5 ----- src/search.cpp | 35 ++++++++++++++++++----------------- 2 files changed, 18 insertions(+), 22 deletions(-) diff --git a/src/position.h b/src/position.h index 8dbf1493..7b6165f3 100644 --- a/src/position.h +++ b/src/position.h @@ -352,11 +352,6 @@ inline bool Position::is_chess960() const { return chess960; } -inline bool Position::capture_or_promotion(Move m) const { - assert(is_ok(m)); - return type_of(m) != NORMAL ? type_of(m) != CASTLING : !empty(to_sq(m)); -} - inline bool Position::capture(Move m) const { assert(is_ok(m)); // Castling is encoded as "king captures rook" diff --git a/src/search.cpp b/src/search.cpp index 672abc05..2d24c313 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -554,7 +554,7 @@ namespace { Depth extension, newDepth; Value bestValue, value, ttValue, eval, maxValue, probCutBeta; bool givesCheck, improving, didLMR, priorCapture; - bool captureOrPromotion, doFullDepthSearch, moveCountPruning, ttCapture; + bool capture, doFullDepthSearch, moveCountPruning, ttCapture; Piece movedPiece; int moveCount, captureCount, quietCount, bestMoveCount, improvement, complexity; @@ -624,7 +624,7 @@ namespace { ttValue = ss->ttHit ? value_from_tt(tte->value(), ss->ply, pos.rule50_count()) : VALUE_NONE; ttMove = rootNode ? thisThread->rootMoves[thisThread->pvIdx].pv[0] : ss->ttHit ? tte->move() : MOVE_NONE; - ttCapture = ttMove && pos.capture_or_promotion(ttMove); + ttCapture = ttMove && pos.capture(ttMove); if (!excludedMove) ss->ttPv = PvNode || (ss->ttHit && tte->is_pv()); @@ -865,12 +865,13 @@ namespace { MovePicker mp(pos, ttMove, probCutBeta - ss->staticEval, depth - 3, &captureHistory); bool ttPv = ss->ttPv; + bool captureOrPromotion; ss->ttPv = false; while ((move = mp.next_move()) != MOVE_NONE) if (move != excludedMove && pos.legal(move)) { - assert(pos.capture_or_promotion(move)); + assert(pos.capture(move) || promotion_type(move) == QUEEN); captureOrPromotion = true; @@ -987,7 +988,7 @@ moves_loop: // When in check, search starts here (ss+1)->pv = nullptr; extension = 0; - captureOrPromotion = pos.capture_or_promotion(move); + capture = pos.capture(move); movedPiece = pos.moved_piece(move); givesCheck = pos.gives_check(move); @@ -1007,7 +1008,7 @@ moves_loop: // When in check, search starts here // Reduced depth of the next LMR search int lmrDepth = std::max(newDepth - reduction(improving, depth, moveCount, delta, thisThread->rootDelta), 0); - if ( captureOrPromotion + if ( capture || givesCheck) { // Futility pruning for captures (~0 Elo) @@ -1122,7 +1123,7 @@ moves_loop: // When in check, search starts here // Update the current move (this must be done after singular extension search) ss->currentMove = move; ss->continuationHistory = &thisThread->continuationHistory[ss->inCheck] - [captureOrPromotion] + [capture] [movedPiece] [to_sq(move)]; @@ -1138,7 +1139,7 @@ moves_loop: // When in check, search starts here if ( depth >= 2 && moveCount > 1 + (PvNode && ss->ply <= 1) && ( !ss->ttPv - || !captureOrPromotion + || !capture || (cutNode && (ss-1)->moveCount > 1))) { Depth r = reduction(improving, depth, moveCount, delta, thisThread->rootDelta); @@ -1215,7 +1216,7 @@ moves_loop: // When in check, search starts here int bonus = value > alpha ? stat_bonus(newDepth) : -stat_bonus(newDepth); - if (captureOrPromotion) + if (capture) bonus /= 6; update_continuation_histories(ss, movedPiece, to_sq(move), bonus); @@ -1306,10 +1307,10 @@ moves_loop: // When in check, search starts here // If the move is worse than some previously searched move, remember it to update its stats later if (move != bestMove) { - if (captureOrPromotion && captureCount < 32) + if (capture && captureCount < 32) capturesSearched[captureCount++] = move; - else if (!captureOrPromotion && quietCount < 64) + else if (!capture && quietCount < 64) quietsSearched[quietCount++] = move; } } @@ -1394,7 +1395,7 @@ moves_loop: // When in check, search starts here Move ttMove, move, bestMove; Depth ttDepth; Value bestValue, value, ttValue, futilityValue, futilityBase; - bool pvHit, givesCheck, captureOrPromotion; + bool pvHit, givesCheck, capture; int moveCount; if (PvNode) @@ -1503,7 +1504,7 @@ moves_loop: // When in check, search starts here continue; givesCheck = pos.gives_check(move); - captureOrPromotion = pos.capture_or_promotion(move); + capture = pos.capture(move); moveCount++; @@ -1543,12 +1544,12 @@ moves_loop: // When in check, search starts here ss->currentMove = move; ss->continuationHistory = &thisThread->continuationHistory[ss->inCheck] - [captureOrPromotion] + [capture] [pos.moved_piece(move)] [to_sq(move)]; // Continuation history based pruning (~2 Elo) - if ( !captureOrPromotion + if ( !capture && bestValue > VALUE_TB_LOSS_IN_MAX_PLY && (*contHist[0])[pos.moved_piece(move)][to_sq(move)] < CounterMovePruneThreshold && (*contHist[1])[pos.moved_piece(move)][to_sq(move)] < CounterMovePruneThreshold) @@ -1557,11 +1558,11 @@ moves_loop: // When in check, search starts here // movecount pruning for quiet check evasions if ( bestValue > VALUE_TB_LOSS_IN_MAX_PLY && quietCheckEvasions > 1 - && !captureOrPromotion + && !capture && ss->inCheck) continue; - quietCheckEvasions += !captureOrPromotion && ss->inCheck; + quietCheckEvasions += !capture && ss->inCheck; // Make and search the move pos.do_move(move, st, givesCheck); @@ -1680,7 +1681,7 @@ moves_loop: // When in check, search starts here bonus2 = bestValue > beta + PawnValueMg ? bonus1 // larger bonus : stat_bonus(depth); // smaller bonus - if (!pos.capture_or_promotion(bestMove)) + if (!pos.capture(bestMove)) { // Increase stats for the best move in case it was a quiet move update_quiet_stats(pos, ss, bestMove, bonus2); From 08e0f52b77edb929989c68c49e954b9bc5d7d67e Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Mon, 28 Mar 2022 14:15:56 +0300 Subject: [PATCH 102/105] In movepicker increase priority for moves that evade a capture This idea is a mix of koivisto idea of threat history and heuristic that was simplified some time ago in LMR - decreasing reduction for moves that evade a capture. Instead of doing so in LMR this patch does it in movepicker - to do this it calculates squares that are attacked by different piece types and pieces that are located on this squares and boosts up weight of moves that make this pieces land on a square that is not under threat. Boost is greater for pieces with bigger material values. Special thanks to koivisto and seer authors for explaining me ideas behind threat history. Passed STC: https://tests.stockfishchess.org/tests/view/62406e473b32264b9aa1478b LLR: 2.94 (-2.94,2.94) <0.00,2.50> Total: 19816 W: 5320 L: 5072 D: 9424 Ptnml(0-2): 86, 2165, 5172, 2385, 100 Passed LTC: https://tests.stockfishchess.org/tests/view/62407f2e3b32264b9aa149c8 LLR: 2.94 (-2.94,2.94) <0.50,3.00> Total: 51200 W: 13805 L: 13500 D: 23895 Ptnml(0-2): 44, 5023, 15164, 5322, 47 closes https://github.com/official-stockfish/Stockfish/pull/3970 bench 7736491 --- src/movepick.cpp | 75 +++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 74 insertions(+), 1 deletion(-) diff --git a/src/movepick.cpp b/src/movepick.cpp index 77453a45..ce82a59b 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -97,6 +97,44 @@ MovePicker::MovePicker(const Position& p, Move ttm, Value th, Depth d, const Cap && pos.see_ge(ttm, threshold)); } +//squares threatened by pawn attacks +template +Bitboard threatsByPawn (const Position& pos) +{ + return pawn_attacks_bb(pos.pieces(Us, PAWN)); +} + +//squares threatened by minor attacks +template +Bitboard threatsByMinor (const Position& pos) +{ + Bitboard our = pos.pieces(Us, KNIGHT, BISHOP); + Bitboard threats = 0; + while (our) + { + Square s = pop_lsb(our); + if (type_of(pos.piece_on(s)) == KNIGHT) + threats |= attacks_bb(s, pos.pieces()); + else + threats |= attacks_bb(s, pos.pieces()); + } + return threats; +} + +//squares threatened by rook attacks +template +Bitboard threatsByRook (const Position& pos) +{ + Bitboard our = pos.pieces(Us, ROOK); + Bitboard threats = 0; + while (our) + { + Square s = pop_lsb(our); + threats |= attacks_bb(s, pos.pieces()); + } + return threats; +} + /// MovePicker::score() assigns a numerical value to each move in a list, used /// for sorting. Captures are ordered by Most Valuable Victim (MVV), preferring /// captures with a good history. Quiets moves are ordered using the histories. @@ -105,6 +143,35 @@ void MovePicker::score() { static_assert(Type == CAPTURES || Type == QUIETS || Type == EVASIONS, "Wrong type"); + Bitboard threatened, threatenedByPawn, threatenedByMinor, threatenedByRook; + if constexpr (Type == QUIETS) + { + // squares threatened by pawns + threatenedByPawn = pos.side_to_move() == WHITE ? threatsByPawn(pos) : threatsByPawn(pos); + // squares threatened by minors or pawns + threatenedByMinor = pos.side_to_move() == WHITE ? threatsByMinor(pos) : threatsByMinor(pos); + threatenedByMinor |= threatenedByPawn; + // squares threatened by rooks, minors or pawns + threatenedByRook = pos.side_to_move() == WHITE ? threatsByRook(pos) : threatsByRook(pos); + threatenedByRook |= threatenedByMinor; + + // pieces threatened by pieces of lesser material value + threatened = pos.side_to_move() == WHITE ? ((pos.pieces(WHITE, QUEEN) & threatenedByRook) | + (pos.pieces(WHITE, ROOK) & threatenedByMinor) | + (pos.pieces(WHITE, KNIGHT, BISHOP) & threatenedByPawn)) + : ((pos.pieces(BLACK, QUEEN) & threatenedByRook) | + (pos.pieces(BLACK, ROOK) & threatenedByMinor) | + (pos.pieces(BLACK, KNIGHT, BISHOP) & threatenedByPawn)); + } + else + { + // Silence unused variable warning + (void) threatened; + (void) threatenedByPawn; + (void) threatenedByMinor; + (void) threatenedByRook; + } + for (auto& m : *this) if constexpr (Type == CAPTURES) m.value = 6 * int(PieceValue[MG][pos.piece_on(to_sq(m))]) @@ -115,7 +182,13 @@ void MovePicker::score() { + 2 * (*continuationHistory[0])[pos.moved_piece(m)][to_sq(m)] + (*continuationHistory[1])[pos.moved_piece(m)][to_sq(m)] + (*continuationHistory[3])[pos.moved_piece(m)][to_sq(m)] - + (*continuationHistory[5])[pos.moved_piece(m)][to_sq(m)]; + + (*continuationHistory[5])[pos.moved_piece(m)][to_sq(m)] + + (threatened & from_sq(m) ? + (type_of(pos.piece_on(from_sq(m))) == QUEEN && !(to_sq(m) & threatenedByRook) ? 50000 + : type_of(pos.piece_on(from_sq(m))) == ROOK && !(to_sq(m) & threatenedByMinor) ? 25000 + : !(to_sq(m) & threatenedByPawn) ? 15000 + : 0) + : 0); else // Type == EVASIONS { From 471d93063a8fc1803a4a34397fe39e2344a05d76 Mon Sep 17 00:00:00 2001 From: Topologist Date: Mon, 28 Mar 2022 11:50:08 +0200 Subject: [PATCH 103/105] Play more positional in endgames This patch chooses the delta value (which skews the nnue evaluation between positional and materialistic) depending on the material: If the material is low, delta will be higher and the evaluation is shifted to the positional value. If the material is high, the evaluation will be shifted to the psqt value. I don't think slightly negative values of delta should be a concern. Passed STC: https://tests.stockfishchess.org/tests/view/62418513b3b383e86185766f LLR: 2.94 (-2.94,2.94) <0.00,2.50> Total: 28808 W: 7832 L: 7564 D: 13412 Ptnml(0-2): 147, 3186, 7505, 3384, 182 Passed LTC: https://tests.stockfishchess.org/tests/view/62419137b3b383e861857842 LLR: 2.96 (-2.94,2.94) <0.50,3.00> Total: 58632 W: 15776 L: 15450 D: 27406 Ptnml(0-2): 42, 5889, 17149, 6173, 63 closes https://github.com/official-stockfish/Stockfish/pull/3971 Bench: 7588855 --- src/nnue/evaluate_nnue.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nnue/evaluate_nnue.cpp b/src/nnue/evaluate_nnue.cpp index 9254e36f..9ee599f4 100644 --- a/src/nnue/evaluate_nnue.cpp +++ b/src/nnue/evaluate_nnue.cpp @@ -143,7 +143,7 @@ namespace Stockfish::Eval::NNUE { // overaligning stack variables with alignas() doesn't work correctly. constexpr uint64_t alignment = CacheLineSize; - int delta = 7; + int delta = 10 - pos.non_pawn_material() / 1515; #if defined(ALIGNAS_ON_STACK_VARIABLES_BROKEN) TransformedFeatureType transformedFeaturesUnaligned[ From 9f6bcb38c032a18c8b1aec318d5c7255827f9c7b Mon Sep 17 00:00:00 2001 From: mstembera Date: Wed, 30 Mar 2022 18:14:27 -0700 Subject: [PATCH 104/105] Minor cleanups simplify and relocate to position.cpp some of the recent threat calculations used in the movepicker. passed STC: https://tests.stockfishchess.org/tests/view/62468c301f682ea45ce3b3b9 LLR: 2.96 (-2.94,2.94) <-2.25,0.25> Total: 76544 W: 20247 L: 20152 D: 36145 Ptnml(0-2): 327, 8113, 21317, 8168, 347 closes https://github.com/official-stockfish/Stockfish/pull/3972 No functional change --- src/misc.h | 9 +++---- src/movepick.cpp | 69 ++++++++++-------------------------------------- src/position.h | 18 ++++++++++++- 3 files changed, 34 insertions(+), 62 deletions(-) diff --git a/src/misc.h b/src/misc.h index dcef22a4..2fd2b408 100644 --- a/src/misc.h +++ b/src/misc.h @@ -90,9 +90,6 @@ static inline const bool IsLittleEndian = (Le.c[0] == 4); class RunningAverage { public: - // Constructor - RunningAverage() {} - // Reset the running average to rational value p / q void set(int64_t p, int64_t q) { average = p * PERIOD * RESOLUTION / q; } @@ -102,10 +99,10 @@ class RunningAverage { { average = RESOLUTION * v + (PERIOD - 1) * average / PERIOD; } // Test if average is strictly greater than rational a / b - bool is_greater(int64_t a, int64_t b) - { return b * average > a * PERIOD * RESOLUTION ; } + bool is_greater(int64_t a, int64_t b) const + { return b * average > a * (PERIOD * RESOLUTION); } - int64_t value() + int64_t value() const { return average / (PERIOD * RESOLUTION); } private : diff --git a/src/movepick.cpp b/src/movepick.cpp index ce82a59b..b0166c6e 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -18,6 +18,7 @@ #include +#include "bitboard.h" #include "movepick.h" namespace Stockfish { @@ -97,44 +98,6 @@ MovePicker::MovePicker(const Position& p, Move ttm, Value th, Depth d, const Cap && pos.see_ge(ttm, threshold)); } -//squares threatened by pawn attacks -template -Bitboard threatsByPawn (const Position& pos) -{ - return pawn_attacks_bb(pos.pieces(Us, PAWN)); -} - -//squares threatened by minor attacks -template -Bitboard threatsByMinor (const Position& pos) -{ - Bitboard our = pos.pieces(Us, KNIGHT, BISHOP); - Bitboard threats = 0; - while (our) - { - Square s = pop_lsb(our); - if (type_of(pos.piece_on(s)) == KNIGHT) - threats |= attacks_bb(s, pos.pieces()); - else - threats |= attacks_bb(s, pos.pieces()); - } - return threats; -} - -//squares threatened by rook attacks -template -Bitboard threatsByRook (const Position& pos) -{ - Bitboard our = pos.pieces(Us, ROOK); - Bitboard threats = 0; - while (our) - { - Square s = pop_lsb(our); - threats |= attacks_bb(s, pos.pieces()); - } - return threats; -} - /// MovePicker::score() assigns a numerical value to each move in a list, used /// for sorting. Captures are ordered by Most Valuable Victim (MVV), preferring /// captures with a good history. Quiets moves are ordered using the histories. @@ -146,26 +109,22 @@ void MovePicker::score() { Bitboard threatened, threatenedByPawn, threatenedByMinor, threatenedByRook; if constexpr (Type == QUIETS) { + Color us = pos.side_to_move(); // squares threatened by pawns - threatenedByPawn = pos.side_to_move() == WHITE ? threatsByPawn(pos) : threatsByPawn(pos); + threatenedByPawn = pos.attacks_by(~us); // squares threatened by minors or pawns - threatenedByMinor = pos.side_to_move() == WHITE ? threatsByMinor(pos) : threatsByMinor(pos); - threatenedByMinor |= threatenedByPawn; + threatenedByMinor = pos.attacks_by(~us) | pos.attacks_by(~us) | threatenedByPawn; // squares threatened by rooks, minors or pawns - threatenedByRook = pos.side_to_move() == WHITE ? threatsByRook(pos) : threatsByRook(pos); - threatenedByRook |= threatenedByMinor; + threatenedByRook = pos.attacks_by(~us) | threatenedByMinor; // pieces threatened by pieces of lesser material value - threatened = pos.side_to_move() == WHITE ? ((pos.pieces(WHITE, QUEEN) & threatenedByRook) | - (pos.pieces(WHITE, ROOK) & threatenedByMinor) | - (pos.pieces(WHITE, KNIGHT, BISHOP) & threatenedByPawn)) - : ((pos.pieces(BLACK, QUEEN) & threatenedByRook) | - (pos.pieces(BLACK, ROOK) & threatenedByMinor) | - (pos.pieces(BLACK, KNIGHT, BISHOP) & threatenedByPawn)); + threatened = (pos.pieces(us, QUEEN) & threatenedByRook) + | (pos.pieces(us, ROOK) & threatenedByMinor) + | (pos.pieces(us, KNIGHT, BISHOP) & threatenedByPawn); } else { - // Silence unused variable warning + // Silence unused variable warnings (void) threatened; (void) threatenedByPawn; (void) threatenedByMinor; @@ -184,11 +143,11 @@ void MovePicker::score() { + (*continuationHistory[3])[pos.moved_piece(m)][to_sq(m)] + (*continuationHistory[5])[pos.moved_piece(m)][to_sq(m)] + (threatened & from_sq(m) ? - (type_of(pos.piece_on(from_sq(m))) == QUEEN && !(to_sq(m) & threatenedByRook) ? 50000 - : type_of(pos.piece_on(from_sq(m))) == ROOK && !(to_sq(m) & threatenedByMinor) ? 25000 - : !(to_sq(m) & threatenedByPawn) ? 15000 - : 0) - : 0); + (type_of(pos.moved_piece(m)) == QUEEN && !(to_sq(m) & threatenedByRook) ? 50000 + : type_of(pos.moved_piece(m)) == ROOK && !(to_sq(m) & threatenedByMinor) ? 25000 + : !(to_sq(m) & threatenedByPawn) ? 15000 + : 0) + : 0); else // Type == EVASIONS { diff --git a/src/position.h b/src/position.h index 7b6165f3..e5585818 100644 --- a/src/position.h +++ b/src/position.h @@ -120,12 +120,12 @@ public: Bitboard attackers_to(Square s) const; Bitboard attackers_to(Square s, Bitboard occupied) const; Bitboard slider_blockers(Bitboard sliders, Square s, Bitboard& pinners) const; + template Bitboard attacks_by(Color c) const; // Properties of moves bool legal(Move m) const; bool pseudo_legal(const Move m) const; bool capture(Move m) const; - bool capture_or_promotion(Move m) const; bool gives_check(Move m) const; Piece moved_piece(Move m) const; Piece captured_piece() const; @@ -285,6 +285,22 @@ inline Bitboard Position::attackers_to(Square s) const { return attackers_to(s, pieces()); } +template +inline Bitboard Position::attacks_by(Color c) const { + + if constexpr (Pt == PAWN) + return c == WHITE ? pawn_attacks_bb(pieces(WHITE, PAWN)) + : pawn_attacks_bb(pieces(BLACK, PAWN)); + else + { + Bitboard threats = 0; + Bitboard attackers = pieces(c, Pt); + while (attackers) + threats |= attacks_bb(pop_lsb(attackers), pieces()); + return threats; + } +} + inline Bitboard Position::checkers() const { return st->checkersBB; } From 19a90b45bceb69aa62b5c85366343a7d1cfc695f Mon Sep 17 00:00:00 2001 From: Topologist Date: Sat, 9 Apr 2022 08:55:40 +0200 Subject: [PATCH 105/105] Use NNUE in low piece endgames close to the root. This patch enforces that NNUE evaluation is used for endgame positions at shallow depth (depth <= 9). Classic evaluation will still be used for high imbalance positions when the depth is high or there are many pieces. Passed STC: https://tests.stockfishchess.org/tests/view/624c193b3a8a6ac93892dc27 LLR: 2.94 (-2.94,2.94) <0.00,2.50> Total: 255840 W: 68024 L: 67362 D: 120454 Ptnml(0-2): 1074, 27089, 70926, 27763, 1068 Passed LTC: https://tests.stockfishchess.org/tests/view/624e8675e9e7821808467f77 LLR: 2.94 (-2.94,2.94) <0.50,3.00> Total: 67088 W: 17784 L: 17454 D: 31850 Ptnml(0-2): 45, 6209, 20715, 6521, 54 closes https://github.com/official-stockfish/Stockfish/pull/3978 bench: 6602222 --- src/evaluate.cpp | 4 +++- src/search.cpp | 1 + src/thread.h | 2 +- 3 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index e9376aa6..d9180f2b 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -1088,7 +1088,8 @@ Value Eval::evaluate(const Position& pos) { // Deciding between classical and NNUE eval (~10 Elo): for high PSQ imbalance we use classical, // but we switch to NNUE during long shuffling or with high material on the board. if ( !useNNUE - || abs(eg_value(pos.psq_score())) * 5 > (856 + pos.non_pawn_material() / 64) * (5 + pos.rule50_count())) + || ((pos.this_thread()->depth > 9 || pos.count() > 7) && + abs(eg_value(pos.psq_score())) * 5 > (856 + pos.non_pawn_material() / 64) * (5 + pos.rule50_count()))) { v = Evaluation(pos).value(); // classical useClassical = abs(v) >= 297; @@ -1138,6 +1139,7 @@ std::string Eval::trace(Position& pos) { std::memset(scores, 0, sizeof(scores)); // Reset any global variable used in eval + pos.this_thread()->depth = 0; pos.this_thread()->trend = SCORE_ZERO; pos.this_thread()->bestValue = VALUE_ZERO; pos.this_thread()->optimism[WHITE] = VALUE_ZERO; diff --git a/src/search.cpp b/src/search.cpp index 2d24c313..fa73dce5 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -560,6 +560,7 @@ namespace { // Step 1. Initialize node Thread* thisThread = pos.this_thread(); + thisThread->depth = depth; ss->inCheck = pos.checkers(); priorCapture = pos.captured_piece(); Color us = pos.side_to_move(); diff --git a/src/thread.h b/src/thread.h index 594a8ea2..8027855a 100644 --- a/src/thread.h +++ b/src/thread.h @@ -69,7 +69,7 @@ public: Position rootPos; StateInfo rootState; Search::RootMoves rootMoves; - Depth rootDepth, completedDepth; + Depth rootDepth, completedDepth, depth; Value rootDelta; CounterMoveHistory counterMoves; ButterflyHistory mainHistory;