From 9d6dab06a8274c4e09b437110f86bdb1ea7edb0f Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Sun, 5 May 2024 03:10:26 +0300 Subject: [PATCH 01/44] simplify moveCountPruning no (significant) speedup upon renewed testing Passed stc: LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 88992 W: 22779 L: 22633 D: 43580 Ptnml(0-2): 137, 8706, 26681, 8818, 154 https://tests.stockfishchess.org/tests/view/6636c4844b68b70d85800dae closes https://github.com/official-stockfish/Stockfish/pull/5213 No functional change. --- src/search.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 684b760ec..1d0cb4ab6 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -960,8 +960,7 @@ moves_loop: // When in check, search starts here if (!rootNode && pos.non_pawn_material(us) && bestValue > VALUE_TB_LOSS_IN_MAX_PLY) { // Skip quiet moves if movecount exceeds our FutilityMoveCount threshold (~8 Elo) - if (!moveCountPruning) - moveCountPruning = moveCount >= futility_move_count(improving, depth); + moveCountPruning = moveCount >= futility_move_count(improving, depth); // Reduced depth of the next LMR search int lmrDepth = newDepth - r; From 3b4ddf4ae6362ddef063cc644d1466754015482e Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Mon, 6 May 2024 20:18:12 +0300 Subject: [PATCH 02/44] Simplify away conthist 3 from statscore Following previous elo gainer that gained by making conthist 3 less important in pruning this patch simplifies away this history from calculation of statscore. Passed STC: https://tests.stockfishchess.org/tests/view/6637aa7e9819650825aa93e0 LLR: 3.00 (-2.94,2.94) <-1.75,0.25> Total: 35392 W: 9352 L: 9120 D: 16920 Ptnml(0-2): 141, 4145, 8888, 4385, 137 Passed LTC: https://tests.stockfishchess.org/tests/view/66383cd8493aaaf4b7ea90c5 LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 33948 W: 8714 L: 8503 D: 16731 Ptnml(0-2): 39, 3701, 9270, 3938, 26 closes https://github.com/official-stockfish/Stockfish/pull/5220 Bench: 2508571 --- src/search.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 1d0cb4ab6..d9f997e8e 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1149,8 +1149,7 @@ moves_loop: // When in check, search starts here ss->statScore = 2 * thisThread->mainHistory[us][move.from_to()] + (*contHist[0])[movedPiece][move.to_sq()] - + (*contHist[1])[movedPiece][move.to_sq()] - + (*contHist[3])[movedPiece][move.to_sq()] - 5078; + + (*contHist[1])[movedPiece][move.to_sq()] - 5078; // Decrease/increase reduction for moves with a good/bad history (~8 Elo) r -= ss->statScore / (17662 - std::min(depth, 16) * 105); @@ -1569,9 +1568,12 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta, break; // Continuation history based pruning (~3 Elo) - if (!capture && (*contHist[0])[pos.moved_piece(move)][move.to_sq()] - + (*contHist[1])[pos.moved_piece(move)][move.to_sq()] - + thisThread->pawnHistory[pawn_structure_index(pos)][pos.moved_piece(move)][move.to_sq()] <= 4000) + if (!capture + && (*contHist[0])[pos.moved_piece(move)][move.to_sq()] + + (*contHist[1])[pos.moved_piece(move)][move.to_sq()] + + thisThread->pawnHistory[pawn_structure_index(pos)][pos.moved_piece(move)] + [move.to_sq()] + <= 4000) continue; // Do not search moves with bad enough SEE values (~5 Elo) From 23439e4096bc28deb2e4e935f24c5ddb22999dc5 Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Tue, 7 May 2024 09:27:04 +0300 Subject: [PATCH 03/44] Remove conthist 3 from moves loop pruning Followup to previous gainer that made it twice less impactful there - this patch removes it entirely as a simplification. Passed STC: https://tests.stockfishchess.org/tests/view/6637aa7e9819650825aa93e0 LLR: 2.93 (-2.94,2.94) <-1.75,0.25> Total: 26208 W: 6930 L: 6694 D: 12584 Ptnml(0-2): 113, 2997, 6652, 3225, 117 Passed LTC: https://tests.stockfishchess.org/tests/view/66383cba493aaaf4b7ea90c2 LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 67866 W: 17294 L: 17118 D: 33454 Ptnml(0-2): 46, 7627, 18415, 7795, 50 closes https://github.com/official-stockfish/Stockfish/pull/5221 Bench: 2691699 --- src/search.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index d9f997e8e..448da7e25 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -990,7 +990,6 @@ moves_loop: // When in check, search starts here int history = (*contHist[0])[movedPiece][move.to_sq()] + (*contHist[1])[movedPiece][move.to_sq()] - + (*contHist[3])[movedPiece][move.to_sq()] / 2 + thisThread->pawnHistory[pawn_structure_index(pos)][movedPiece][move.to_sq()]; // Continuation history based pruning (~2 Elo) From 574ad14b323465314c8d5d5a81af995cb58b07c9 Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Thu, 9 May 2024 02:56:43 +0300 Subject: [PATCH 04/44] Simplify depth formula based on score improvement Simplify depth formula based on score improvement. This idea was first tried by cj5716 Passed STC: LLR: 2.93 (-2.94,2.94) <-1.75,0.25> Total: 347104 W: 89683 L: 89804 D: 167617 Ptnml(0-2): 1357, 38824, 93307, 38711, 1353 https://tests.stockfishchess.org/tests/view/66378edf9819650825aa75d0 Passed LTC: LLR: 2.93 (-2.94,2.94) <-1.75,0.25> Total: 63000 W: 15851 L: 15694 D: 31455 Ptnml(0-2): 22, 5396, 20499, 5569, 14 https://tests.stockfishchess.org/tests/view/663c04e5c0b75d7f7b97d461 closes https://github.com/official-stockfish/Stockfish/pull/5225 Bench: 2691699 Co-Authored-By: cj5716 <125858804+cj5716@users.noreply.github.com> --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 448da7e25..fdf9871cd 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1288,7 +1288,7 @@ moves_loop: // When in check, search starts here else { // Reduce other moves if we have found at least one score improvement (~2 Elo) - if (depth > 2 && depth < 13 && beta < 15868 && value > -14630) + if (depth > 2 && depth < 13 && abs(value) < VALUE_TB_WIN_IN_MAX_PLY) depth -= 2; assert(depth > 0); From c43425b0b1167665b2f9520690e639c80977c067 Mon Sep 17 00:00:00 2001 From: Shawn Xu Date: Wed, 8 May 2024 14:26:01 -0700 Subject: [PATCH 05/44] Simplify Away Negative Extension This patch simplifies away the negative extension applied when the value returned by the transposition table is assumed to fail low over the value of reduced search. Passed STC: LLR: 2.99 (-2.94,2.94) <-1.75,0.25> Total: 248736 W: 64293 L: 64302 D: 120141 Ptnml(0-2): 925, 29833, 62831, 29884, 895 https://tests.stockfishchess.org/tests/view/663bee3bca93dad645f7f64a Passed LTC: LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 254970 W: 64289 L: 64308 D: 126373 Ptnml(0-2): 110, 28428, 70422, 28421, 104 https://tests.stockfishchess.org/tests/view/663c11f0c0b75d7f7b97d4bb closes https://github.com/official-stockfish/Stockfish/pull/5226 Bench: 2353057 --- src/search.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index fdf9871cd..4572ffc90 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1087,10 +1087,6 @@ moves_loop: // When in check, search starts here // If we are on a cutNode but the ttMove is not assumed to fail high over current beta (~1 Elo) else if (cutNode) extension = -2; - - // If the ttMove is assumed to fail low over the value of the reduced search (~1 Elo) - else if (ttValue <= value) - extension = -1; } // Extension for capturing the previous moved piece (~0 Elo on STC, ~1 Elo on LTC) From b8812138e8e4e6ebd9d1c46ca9da15ddab1eb1ae Mon Sep 17 00:00:00 2001 From: xu-shawn <50402888+xu-shawn@users.noreply.github.com> Date: Thu, 9 May 2024 00:11:09 -0700 Subject: [PATCH 06/44] Fix usage of abs vs std::abs closes https://github.com/official-stockfish/Stockfish/pull/5229 no functional change --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 4572ffc90..6c30c3e91 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1284,7 +1284,7 @@ moves_loop: // When in check, search starts here else { // Reduce other moves if we have found at least one score improvement (~2 Elo) - if (depth > 2 && depth < 13 && abs(value) < VALUE_TB_WIN_IN_MAX_PLY) + if (depth > 2 && depth < 13 && std::abs(value) < VALUE_TB_WIN_IN_MAX_PLY) depth -= 2; assert(depth > 0); From 540545d12792dc554e3a4cd1b09633c31a16d31b Mon Sep 17 00:00:00 2001 From: Shawn Xu Date: Thu, 9 May 2024 00:38:43 -0700 Subject: [PATCH 07/44] simplify away quietCheckEvasions pruning simplifies away the pruning of quiet evasion moves in quiescent search. Passed STC: LLR: 2.98 (-2.94,2.94) <-1.75,0.25> Total: 343520 W: 88356 L: 88470 D: 166694 Ptnml(0-2): 1061, 40073, 89706, 39759, 1161 https://tests.stockfishchess.org/tests/view/663c7ddfc0b75d7f7b980f3b Passed LTC: LLR: 2.95 (-2.94,2.94) <-1.75,0.25> Total: 168744 W: 42454 L: 42384 D: 83906 Ptnml(0-2): 75, 18678, 46782, 18776, 61 https://tests.stockfishchess.org/tests/view/663ce34fc0b75d7f7b981ed9 closes https://github.com/official-stockfish/Stockfish/pull/5231 bench 3681552 --- src/search.cpp | 10 ---------- 1 file changed, 10 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 6c30c3e91..3867a3975 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1502,8 +1502,6 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta, MovePicker mp(pos, ttMove, depth, &thisThread->mainHistory, &thisThread->captureHistory, contHist, &thisThread->pawnHistory); - int quietCheckEvasions = 0; - // Step 5. Loop through all pseudo-legal moves until no moves remain // or a beta cutoff occurs. while ((move = mp.next_move()) != Move::none()) @@ -1556,12 +1554,6 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta, } } - // We prune after the second quiet check evasion move, where being 'in check' is - // implicitly checked through the counter, and being a 'quiet move' apart from - // being a tt move is assumed after an increment because captures are pushed ahead. - if (quietCheckEvasions > 1) - break; - // Continuation history based pruning (~3 Elo) if (!capture && (*contHist[0])[pos.moved_piece(move)][move.to_sq()] @@ -1585,8 +1577,6 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta, &thisThread ->continuationHistory[ss->inCheck][capture][pos.moved_piece(move)][move.to_sq()]; - quietCheckEvasions += !capture && ss->inCheck; - // Step 7. Make and search the move thisThread->nodes.fetch_add(1, std::memory_order_relaxed); pos.do_move(move, st, givesCheck); From 813c5aa5329011e218dad8dc53d61504cecadc3f Mon Sep 17 00:00:00 2001 From: Muzhen Gaming <61100393+XInTheDark@users.noreply.github.com> Date: Sun, 12 May 2024 17:49:30 +0800 Subject: [PATCH 08/44] VVLTC search tune Tuned at 111k games of VVLTC. Passed VVLTC 1st sprt: https://tests.stockfishchess.org/tests/view/664090c6d163897c63214324 LLR: 2.94 (-2.94,2.94) <0.00,2.00> Total: 83046 W: 21071 L: 20747 D: 41228 Ptnml(0-2): 2, 7574, 26048, 7896, 3 Passed VVLTC 2nd sprt: https://tests.stockfishchess.org/tests/view/6640cb2abaa6260a5688dc17 LLR: 2.95 (-2.94,2.94) <0.50,2.50> Total: 68630 W: 17620 L: 17270 D: 33740 Ptnml(0-2): 4, 6242, 21471, 6596, 2 closes https://github.com/official-stockfish/Stockfish/pull/5240 Bench: 1752471 --- src/search.cpp | 84 +++++++++++++++++++++++++------------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 3867a3975..1d9e0d81a 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -59,9 +59,9 @@ static constexpr double EvalLevel[10] = {0.981, 0.956, 0.895, 0.949, 0.913, // Futility margin Value futility_margin(Depth d, bool noTtCutNode, bool improving, bool oppWorsening) { - Value futilityMult = 126 - 46 * noTtCutNode; - Value improvingDeduction = 58 * improving * futilityMult / 32; - Value worseningDeduction = (323 + 52 * improving) * oppWorsening * futilityMult / 1024; + Value futilityMult = 131 - 48 * noTtCutNode; + Value improvingDeduction = 57 * improving * futilityMult / 32; + Value worseningDeduction = (309 + 52 * improving) * oppWorsening * futilityMult / 1024; return futilityMult * d - improvingDeduction - worseningDeduction; } @@ -73,15 +73,15 @@ constexpr int futility_move_count(bool improving, Depth depth) { // Add correctionHistory value to raw staticEval and guarantee evaluation does not hit the tablebase range Value to_corrected_static_eval(Value v, const Worker& w, const Position& pos) { auto cv = w.correctionHistory[pos.side_to_move()][pawn_structure_index(pos)]; - v += cv * std::abs(cv) / 7350; + v += cv * std::abs(cv) / 7179; return std::clamp(v, VALUE_TB_LOSS_IN_MAX_PLY + 1, VALUE_TB_WIN_IN_MAX_PLY - 1); } // History and stats update bonus, based on depth -int stat_bonus(Depth d) { return std::clamp(208 * d - 297, 16, 1406); } +int stat_bonus(Depth d) { return std::clamp(200 * d - 280, 16, 1495); } // History and stats update malus, based on depth -int stat_malus(Depth d) { return (d < 4 ? 520 * d - 312 : 1479); } +int stat_malus(Depth d) { return (d < 4 ? 586 * d - 284 : 1639); } // Add a small random component to draw evaluations to avoid 3-fold blindness Value value_draw(size_t nodes) { return VALUE_DRAW - 1 + Value(nodes & 0x2); } @@ -310,12 +310,12 @@ void Search::Worker::iterative_deepening() { // Reset aspiration window starting size Value avg = rootMoves[pvIdx].averageScore; - delta = 10 + avg * avg / 9530; + delta = 10 + avg * avg / 9474; alpha = std::max(avg - delta, -VALUE_INFINITE); beta = std::min(avg + delta, VALUE_INFINITE); // Adjust optimism based on root move's averageScore (~4 Elo) - optimism[us] = 119 * avg / (std::abs(avg) + 88); + optimism[us] = 117 * avg / (std::abs(avg) + 88); optimism[~us] = -optimism[us]; // Start with a small aspiration window and, in the case of a fail @@ -502,10 +502,10 @@ void Search::Worker::clear() { for (StatsType c : {NoCaptures, Captures}) for (auto& to : continuationHistory[inCheck][c]) for (auto& h : to) - h->fill(-60); + h->fill(-62); for (size_t i = 1; i < reductions.size(); ++i) - reductions[i] = int((18.93 + std::log(size_t(options["Threads"])) / 2) * std::log(i)); + reductions[i] = int((21.19 + std::log(size_t(options["Threads"])) / 2) * std::log(i)); refreshTable.clear(networks); } @@ -738,7 +738,7 @@ Value Search::Worker::search( // Use static evaluation difference to improve quiet move ordering (~9 Elo) if (((ss - 1)->currentMove).is_ok() && !(ss - 1)->inCheck && !priorCapture) { - int bonus = std::clamp(-13 * int((ss - 1)->staticEval + ss->staticEval), -1796, 1526); + int bonus = std::clamp(-12 * int((ss - 1)->staticEval + ss->staticEval), -1749, 1602); bonus = bonus > 0 ? 2 * bonus : bonus / 2; thisThread->mainHistory[~us][((ss - 1)->currentMove).from_to()] << bonus; if (type_of(pos.piece_on(prevSq)) != PAWN && ((ss - 1)->currentMove).type_of() != PROMOTION) @@ -761,7 +761,7 @@ Value Search::Worker::search( // If eval is really low check with qsearch if it can exceed alpha, if it can't, // return a fail low. // Adjust razor margin according to cutoffCnt. (~1 Elo) - if (eval < alpha - 433 - (302 - 141 * ((ss + 1)->cutoffCnt > 3)) * depth * depth) + if (eval < alpha - 473 - (308 - 138 * ((ss + 1)->cutoffCnt > 3)) * depth * depth) { value = qsearch(pos, ss, alpha - 1, alpha); if (value < alpha) @@ -772,21 +772,21 @@ Value Search::Worker::search( // The depth condition is important for mate finding. if (!ss->ttPv && depth < 11 && eval - futility_margin(depth, cutNode && !ss->ttHit, improving, opponentWorsening) - - (ss - 1)->statScore / 254 + - (ss - 1)->statScore / 258 >= beta && eval >= beta && eval < VALUE_TB_WIN_IN_MAX_PLY && (!ttMove || ttCapture)) return beta > VALUE_TB_LOSS_IN_MAX_PLY ? (eval + beta) / 2 : eval; // Step 9. Null move search with verification search (~35 Elo) - if (!PvNode && (ss - 1)->currentMove != Move::null() && (ss - 1)->statScore < 16993 - && eval >= beta && ss->staticEval >= beta - 19 * depth + 326 && !excludedMove + if (!PvNode && (ss - 1)->currentMove != Move::null() && (ss - 1)->statScore < 16079 + && eval >= beta && ss->staticEval >= beta - 21 * depth + 324 && !excludedMove && pos.non_pawn_material(us) && ss->ply >= thisThread->nmpMinPly && beta > VALUE_TB_LOSS_IN_MAX_PLY) { assert(eval - beta >= 0); // Null move dynamic reduction based on depth and eval - Depth R = std::min(int(eval - beta) / 134, 6) + depth / 3 + 4; + Depth R = std::min(int(eval - beta) / 144, 6) + depth / 3 + 4; ss->currentMove = Move::null(); ss->continuationHistory = &thisThread->continuationHistory[0][0][NO_PIECE][0]; @@ -834,7 +834,7 @@ Value Search::Worker::search( // Step 11. ProbCut (~10 Elo) // If we have a good enough capture (or queen promotion) and a reduced search returns a value // much above beta, we can (almost) safely prune the previous move. - probCutBeta = beta + 159 - 66 * improving; + probCutBeta = beta + 177 - 65 * improving; if ( !PvNode && depth > 3 && std::abs(beta) < VALUE_TB_WIN_IN_MAX_PLY @@ -890,7 +890,7 @@ Value Search::Worker::search( moves_loop: // When in check, search starts here // Step 12. A small Probcut idea, when we are in check (~4 Elo) - probCutBeta = beta + 420; + probCutBeta = beta + 428; if (ss->inCheck && !PvNode && ttCapture && (tte->bound() & BOUND_LOWER) && tte->depth() >= depth - 4 && ttValue >= probCutBeta && std::abs(ttValue) < VALUE_TB_WIN_IN_MAX_PLY && std::abs(beta) < VALUE_TB_WIN_IN_MAX_PLY) @@ -974,15 +974,15 @@ moves_loop: // When in check, search starts here // Futility pruning for captures (~2 Elo) if (!givesCheck && lmrDepth < 7 && !ss->inCheck) { - Value futilityValue = ss->staticEval + 295 + 280 * lmrDepth + Value futilityValue = ss->staticEval + 305 + 272 * lmrDepth + PieceValue[capturedPiece] + captHist / 7; if (futilityValue <= alpha) continue; } // SEE based pruning for captures and checks (~11 Elo) - int seeHist = std::clamp(captHist / 32, -197 * depth, 196 * depth); - if (!pos.see_ge(move, -186 * depth - seeHist)) + int seeHist = std::clamp(captHist / 32, -185 * depth, 182 * depth); + if (!pos.see_ge(move, -176 * depth - seeHist)) continue; } else @@ -993,18 +993,18 @@ moves_loop: // When in check, search starts here + thisThread->pawnHistory[pawn_structure_index(pos)][movedPiece][move.to_sq()]; // Continuation history based pruning (~2 Elo) - if (lmrDepth < 6 && history < -4081 * depth) + if (lmrDepth < 6 && history < -4360 * depth) continue; history += 2 * thisThread->mainHistory[us][move.from_to()]; - lmrDepth += history / 4768; + lmrDepth += history / 4507; Value futilityValue = - ss->staticEval + (bestValue < ss->staticEval - 52 ? 134 : 54) + 142 * lmrDepth; + ss->staticEval + (bestValue < ss->staticEval - 54 ? 142 : 55) + 132 * lmrDepth; // Futility pruning: parent node (~13 Elo) - if (!ss->inCheck && lmrDepth < 13 && futilityValue <= alpha) + if (!ss->inCheck && lmrDepth < 11 && futilityValue <= alpha) { if (bestValue <= futilityValue && std::abs(bestValue) < VALUE_TB_WIN_IN_MAX_PLY && futilityValue < VALUE_TB_WIN_IN_MAX_PLY) @@ -1015,7 +1015,7 @@ moves_loop: // When in check, search starts here lmrDepth = std::max(lmrDepth, 0); // Prune moves with negative SEE (~4 Elo) - if (!pos.see_ge(move, -28 * lmrDepth * lmrDepth)) + if (!pos.see_ge(move, -27 * lmrDepth * lmrDepth)) continue; } } @@ -1035,11 +1035,11 @@ moves_loop: // When in check, search starts here // so changing them requires tests at these types of time controls. // Recursive singular search is avoided. if (!rootNode && move == ttMove && !excludedMove - && depth >= 4 - (thisThread->completedDepth > 32) + ss->ttPv + && depth >= 4 - (thisThread->completedDepth > 33) + ss->ttPv && std::abs(ttValue) < VALUE_TB_WIN_IN_MAX_PLY && (tte->bound() & BOUND_LOWER) && tte->depth() >= depth - 3) { - Value singularBeta = ttValue - (65 + 52 * (ss->ttPv && !PvNode)) * depth / 63; + Value singularBeta = ttValue - (59 + 49 * (ss->ttPv && !PvNode)) * depth / 64; Depth singularDepth = newDepth / 2; ss->excludedMove = move; @@ -1049,10 +1049,10 @@ moves_loop: // When in check, search starts here if (value < singularBeta) { - int doubleMargin = 251 * PvNode - 241 * !ttCapture; + int doubleMargin = 285 * PvNode - 228 * !ttCapture; int tripleMargin = - 135 + 234 * PvNode - 248 * !ttCapture + 124 * (ss->ttPv || !ttCapture); - int quadMargin = 447 + 354 * PvNode - 300 * !ttCapture + 206 * ss->ttPv; + 121 + 238 * PvNode - 259 * !ttCapture + 117 * (ss->ttPv || !ttCapture); + int quadMargin = 471 + 343 * PvNode - 281 * !ttCapture + 217 * ss->ttPv; extension = 1 + (value < singularBeta - doubleMargin) + (value < singularBeta - tripleMargin) @@ -1093,7 +1093,7 @@ moves_loop: // When in check, search starts here else if (PvNode && move == ttMove && move.to_sq() == prevSq && thisThread->captureHistory[movedPiece][move.to_sq()] [type_of(pos.piece_on(move.to_sq()))] - > 4016) + > 4041) extension = 1; } @@ -1144,10 +1144,10 @@ moves_loop: // When in check, search starts here ss->statScore = 2 * thisThread->mainHistory[us][move.from_to()] + (*contHist[0])[movedPiece][move.to_sq()] - + (*contHist[1])[movedPiece][move.to_sq()] - 5078; + + (*contHist[1])[movedPiece][move.to_sq()] - 5313; // Decrease/increase reduction for moves with a good/bad history (~8 Elo) - r -= ss->statScore / (17662 - std::min(depth, 16) * 105); + r -= ss->statScore / (16145 - std::min(depth, 15) * 102); // Step 17. Late moves reduction / extension (LMR, ~117 Elo) if (depth >= 2 && moveCount > 1 + rootNode) @@ -1166,7 +1166,7 @@ moves_loop: // When in check, search starts here { // Adjust full-depth search based on LMR results - if the result // was good enough search deeper, if it was bad enough search shallower. - const bool doDeeperSearch = value > (bestValue + 40 + 2 * newDepth); // (~1 Elo) + const bool doDeeperSearch = value > (bestValue + 41 + 2 * newDepth); // (~1 Elo) const bool doShallowerSearch = value < bestValue + newDepth; // (~2 Elo) newDepth += doDeeperSearch - doShallowerSearch; @@ -1327,9 +1327,9 @@ moves_loop: // When in check, search starts here // Bonus for prior countermove that caused the fail low else if (!priorCapture && prevSq != SQ_NONE) { - int bonus = (depth > 5) + (PvNode || cutNode) + ((ss - 1)->statScore < -14455) - + ((ss - 1)->moveCount > 10) + (!ss->inCheck && bestValue <= ss->staticEval - 130) - + (!(ss - 1)->inCheck && bestValue <= -(ss - 1)->staticEval - 77); + int bonus = (depth > 5) + (PvNode || cutNode) + ((ss - 1)->statScore < -14323) + + ((ss - 1)->moveCount > 10) + (!ss->inCheck && bestValue <= ss->staticEval - 127) + + (!(ss - 1)->inCheck && bestValue <= -(ss - 1)->staticEval - 76); update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq, stat_bonus(depth) * bonus); thisThread->mainHistory[~us][((ss - 1)->currentMove).from_to()] @@ -1488,7 +1488,7 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta, if (bestValue > alpha) alpha = bestValue; - futilityBase = ss->staticEval + 270; + futilityBase = ss->staticEval + 259; } const PieceToHistory* contHist[] = {(ss - 1)->continuationHistory, @@ -1560,11 +1560,11 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta, + (*contHist[1])[pos.moved_piece(move)][move.to_sq()] + thisThread->pawnHistory[pawn_structure_index(pos)][pos.moved_piece(move)] [move.to_sq()] - <= 4000) + <= 4057) continue; // Do not search moves with bad enough SEE values (~5 Elo) - if (!pos.see_ge(move, -69)) + if (!pos.see_ge(move, -68)) continue; } @@ -1630,7 +1630,7 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth Search::Worker::reduction(bool i, Depth d, int mn, int delta) { int reductionScale = reductions[d] * reductions[mn]; - return (reductionScale + 1318 - delta * 760 / rootDelta) / 1024 + (!i && reductionScale > 1066); + return (reductionScale + 1284 - delta * 755 / rootDelta) / 1024 + (!i && reductionScale > 1133); } // elapsed() returns the time elapsed since the search started. If the From d3f081ed8ad749cc7e07c0d85b4e8818678f952f Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Thu, 9 May 2024 21:10:24 +0300 Subject: [PATCH 09/44] Adjust standpat return value in qsearch Instead of returning value itself return value between it and beta for non pv nodes - analogous to what we do after actual search there. Passed STC: https://tests.stockfishchess.org/tests/view/663cb1b4c0b75d7f7b98188e LLR: 2.95 (-2.94,2.94) <0.00,2.00> Total: 131552 W: 34131 L: 33673 D: 63748 Ptnml(0-2): 420, 15446, 33600, 15876, 434 Passed LTC: https://tests.stockfishchess.org/tests/view/663cda5dc0b75d7f7b981c6f LLR: 2.95 (-2.94,2.94) <0.50,2.50> Total: 282798 W: 71658 L: 70833 D: 140307 Ptnml(0-2): 112, 31187, 77979, 32006, 115 closes https://github.com/official-stockfish/Stockfish/pull/5233 Bench: 1606672 --- src/search.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/search.cpp b/src/search.cpp index 1d9e0d81a..ae2b1de23 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1478,6 +1478,8 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta, // Stand pat. Return immediately if static value is at least beta if (bestValue >= beta) { + if (std::abs(bestValue) < VALUE_TB_WIN_IN_MAX_PLY && !PvNode) + bestValue = (3 * bestValue + beta) / 4; if (!ss->ttHit) tte->save(posKey, value_to_tt(bestValue, ss->ply), false, BOUND_LOWER, DEPTH_NONE, Move::none(), unadjustedStaticEval, tt.generation()); From 53f363041cd96be840244f989823781ecd21b658 Mon Sep 17 00:00:00 2001 From: Linmiao Xu Date: Thu, 9 May 2024 13:47:00 -0400 Subject: [PATCH 10/44] Simplify npm constants when adjusting eval Passed non-regression STC: https://tests.stockfishchess.org/tests/view/663d0c4f507ebe1c0e91ec8d LLR: 2.93 (-2.94,2.94) <-1.75,0.25> Total: 162784 W: 41987 L: 41906 D: 78891 Ptnml(0-2): 520, 19338, 41591, 19427, 516 Passed non-regression LTC: https://tests.stockfishchess.org/tests/view/663d20fd507ebe1c0e91f405 LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 457242 W: 115022 L: 115250 D: 226970 Ptnml(0-2): 271, 51566, 125179, 51330, 275 closes https://github.com/official-stockfish/Stockfish/pull/5237 Bench: 2238216 --- src/evaluate.cpp | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 5be7e7a1b..cfe20601e 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -62,15 +62,13 @@ Value Eval::evaluate(const Eval::NNUE::Networks& networks, Value nnue = smallNet ? networks.small.evaluate(pos, &caches.small, true, &nnueComplexity) : networks.big.evaluate(pos, &caches.big, true, &nnueComplexity); - const auto adjustEval = [&](int nnueDiv, int pawnCountConstant, int pawnCountMul, - int npmConstant, int evalDiv, int shufflingConstant) { + const auto adjustEval = [&](int nnueDiv, int pawnCountMul, int evalDiv, int shufflingConstant) { // Blend optimism and eval with nnue complexity and material imbalance optimism += optimism * (nnueComplexity + std::abs(simpleEval - nnue)) / 584; nnue -= nnue * (nnueComplexity * 5 / 3) / nnueDiv; int npm = pos.non_pawn_material() / 64; - v = (nnue * (npm + pawnCountConstant + pawnCountMul * pos.count()) - + optimism * (npmConstant + npm)) + v = (nnue * (npm + 943 + pawnCountMul * pos.count()) + optimism * (npm + 140)) / evalDiv; // Damp down the evaluation linearly when shuffling @@ -79,9 +77,9 @@ Value Eval::evaluate(const Eval::NNUE::Networks& networks, }; if (!smallNet) - adjustEval(32395, 942, 11, 139, 1058, 178); + adjustEval(32395, 11, 1058, 178); else - adjustEval(32793, 944, 9, 140, 1067, 206); + adjustEval(32793, 9, 1067, 206); // 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 0b08953174d222270100690b45fad0dc47c01f98 Mon Sep 17 00:00:00 2001 From: Linmiao Xu Date: Thu, 9 May 2024 14:03:35 -0400 Subject: [PATCH 11/44] Re-evaluate some small net positions for more accurate evals Use main net evals when small net evals hint that higher eval accuracy may be worth the slower eval speeds. With Finny caches, re-evals with the main net are less expensive than before. Original idea by mstembera who I've added as co-author to this PR. Based on reEval tests by mstembera: https://tests.stockfishchess.org/tests/view/65e69187b6345c1b934866e5 https://tests.stockfishchess.org/tests/view/65e863aa0ec64f0526c3e991 A few variants of this patch also passed LTC: https://tests.stockfishchess.org/tests/view/663d2108507ebe1c0e91f407 https://tests.stockfishchess.org/tests/view/663e388c3a2f9702074bc152 Passed STC: https://tests.stockfishchess.org/tests/view/663dadbd1a61d6377f190e2c LLR: 2.93 (-2.94,2.94) <0.00,2.00> Total: 92320 W: 23941 L: 23531 D: 44848 Ptnml(0-2): 430, 10993, 22931, 11349, 457 Passed LTC: https://tests.stockfishchess.org/tests/view/663ef48b2948bf9aa698690c LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 98934 W: 24907 L: 24457 D: 49570 Ptnml(0-2): 48, 10952, 27027, 11382, 58 closes https://github.com/official-stockfish/Stockfish/pull/5238 bench 1876282 Co-Authored-By: mstembera <5421953+mstembera@users.noreply.github.com> --- src/evaluate.cpp | 3 +++ src/evaluate.h | 2 +- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index cfe20601e..b5f28d5ae 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -62,6 +62,9 @@ Value Eval::evaluate(const Eval::NNUE::Networks& networks, Value nnue = smallNet ? networks.small.evaluate(pos, &caches.small, true, &nnueComplexity) : networks.big.evaluate(pos, &caches.big, true, &nnueComplexity); + if (smallNet && (nnue * simpleEval < 0 || std::abs(nnue) < 500)) + nnue = networks.big.evaluate(pos, &caches.big, true, &nnueComplexity); + const auto adjustEval = [&](int nnueDiv, int pawnCountMul, int evalDiv, int shufflingConstant) { // Blend optimism and eval with nnue complexity and material imbalance optimism += optimism * (nnueComplexity + std::abs(simpleEval - nnue)) / 584; diff --git a/src/evaluate.h b/src/evaluate.h index 2d244ff67..afaf35ebe 100644 --- a/src/evaluate.h +++ b/src/evaluate.h @@ -29,7 +29,7 @@ class Position; namespace Eval { -constexpr inline int SmallNetThreshold = 1274; +constexpr inline int SmallNetThreshold = 1174; // 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 From e608eab8dd9f7bd68f192d56d742f621674b8fa8 Mon Sep 17 00:00:00 2001 From: mstembera Date: Sun, 12 May 2024 04:45:01 -0700 Subject: [PATCH 12/44] Optimize update_accumulator_refresh_cache() STC https://tests.stockfishchess.org/tests/view/664105df26ac5f9b286d30e6 LLR: 2.94 (-2.94,2.94) <0.00,2.00> Total: 178528 W: 46235 L: 45750 D: 86543 Ptnml(0-2): 505, 17792, 52142, 18363, 462 Combo of two yellow speedups https://tests.stockfishchess.org/tests/view/6640abf9d163897c63214f5c LLR: -2.93 (-2.94,2.94) <0.00,2.00> Total: 355744 W: 91714 L: 91470 D: 172560 Ptnml(0-2): 913, 36233, 103384, 36381, 961 https://tests.stockfishchess.org/tests/view/6628ce073fe04ce4cefc739c LLR: -2.93 (-2.94,2.94) <0.00,2.00> Total: 627040 W: 162001 L: 161339 D: 303700 Ptnml(0-2): 2268, 72379, 163532, 73105, 2236 closes https://github.com/official-stockfish/Stockfish/pull/5239 No functional change --- src/nnue/nnue_feature_transformer.h | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/nnue/nnue_feature_transformer.h b/src/nnue/nnue_feature_transformer.h index 2b11adefb..bcd14e6fb 100644 --- a/src/nnue/nnue_feature_transformer.h +++ b/src/nnue/nnue_feature_transformer.h @@ -664,7 +664,11 @@ class FeatureTransformer { for (IndexType j = 0; j < HalfDimensions / TileHeight; ++j) { - auto entryTile = reinterpret_cast(&entry.accumulation[j * TileHeight]); + auto accTile = + reinterpret_cast(&accumulator.accumulation[Perspective][j * TileHeight]); + auto entryTile = + reinterpret_cast(&entry.accumulation[j * TileHeight]); + for (IndexType k = 0; k < NumRegs; ++k) acc[k] = entryTile[k]; @@ -679,7 +683,7 @@ class FeatureTransformer { auto columnA = reinterpret_cast(&weights[offsetA]); for (unsigned k = 0; k < NumRegs; ++k) - acc[k] = vec_add_16(vec_sub_16(acc[k], columnR[k]), columnA[k]); + acc[k] = vec_add_16(acc[k], vec_sub_16(columnA[k], columnR[k])); } for (; i < int(removed.size()); ++i) { @@ -702,12 +706,17 @@ class FeatureTransformer { for (IndexType k = 0; k < NumRegs; k++) vec_store(&entryTile[k], acc[k]); + for (IndexType k = 0; k < NumRegs; k++) + vec_store(&accTile[k], acc[k]); } for (IndexType j = 0; j < PSQTBuckets / PsqtTileHeight; ++j) { - auto entryTilePsqt = - reinterpret_cast(&entry.psqtAccumulation[j * PsqtTileHeight]); + auto accTilePsqt = reinterpret_cast( + &accumulator.psqtAccumulation[Perspective][j * PsqtTileHeight]); + auto entryTilePsqt = reinterpret_cast( + &entry.psqtAccumulation[j * PsqtTileHeight]); + for (std::size_t k = 0; k < NumPsqtRegs; ++k) psqt[k] = entryTilePsqt[k]; @@ -732,6 +741,8 @@ class FeatureTransformer { for (std::size_t k = 0; k < NumPsqtRegs; ++k) vec_store_psqt(&entryTilePsqt[k], psqt[k]); + for (std::size_t k = 0; k < NumPsqtRegs; ++k) + vec_store_psqt(&accTilePsqt[k], psqt[k]); } #else @@ -755,8 +766,6 @@ class FeatureTransformer { entry.psqtAccumulation[k] += psqtWeights[index * PSQTBuckets + k]; } -#endif - // The accumulator of the refresh entry has been updated. // Now copy its content to the actual accumulator we were refreshing @@ -765,6 +774,7 @@ class FeatureTransformer { std::memcpy(accumulator.psqtAccumulation[Perspective], entry.psqtAccumulation, sizeof(int32_t) * PSQTBuckets); +#endif for (Color c : {WHITE, BLACK}) entry.byColorBB[c] = pos.pieces(c); From 2682c2127d1360524915f6cd68cbeabfdd19ce26 Mon Sep 17 00:00:00 2001 From: xoto10 <23479932+xoto10@users.noreply.github.com> Date: Mon, 13 May 2024 07:19:18 +0100 Subject: [PATCH 13/44] Use 5% less time on first move Stockfish appears to take too much time on the first move of a game and then not enough on moves 2,3,4... Probably caused by most of the factors that increase time usually applying on the first move. Attempts to give more time to the subsequent moves have not worked so far, but this change to simply reduce first move time by 5% worked. STC 10+0.1 : LLR: 2.96 (-2.94,2.94) <0.00,2.00> Total: 78496 W: 20516 L: 20135 D: 37845 Ptnml(0-2): 340, 8859, 20456, 9266, 327 https://tests.stockfishchess.org/tests/view/663d47bf507ebe1c0e9200ba LTC 60+0.6 : LLR: 2.95 (-2.94,2.94) <0.50,2.50> Total: 94872 W: 24179 L: 23751 D: 46942 Ptnml(0-2): 61, 9743, 27405, 10161, 66 https://tests.stockfishchess.org/tests/view/663e779cbb28828150dd9089 closes https://github.com/official-stockfish/Stockfish/pull/5235 Bench: 1876282 --- src/nnue/nnue_feature_transformer.h | 9 ++++----- src/search.cpp | 3 ++- src/search.h | 1 + src/thread.cpp | 1 + src/timeman.cpp | 11 +++++++---- src/timeman.h | 3 ++- 6 files changed, 17 insertions(+), 11 deletions(-) diff --git a/src/nnue/nnue_feature_transformer.h b/src/nnue/nnue_feature_transformer.h index bcd14e6fb..7b7aada31 100644 --- a/src/nnue/nnue_feature_transformer.h +++ b/src/nnue/nnue_feature_transformer.h @@ -666,8 +666,7 @@ class FeatureTransformer { { auto accTile = reinterpret_cast(&accumulator.accumulation[Perspective][j * TileHeight]); - auto entryTile = - reinterpret_cast(&entry.accumulation[j * TileHeight]); + auto entryTile = reinterpret_cast(&entry.accumulation[j * TileHeight]); for (IndexType k = 0; k < NumRegs; ++k) acc[k] = entryTile[k]; @@ -714,9 +713,9 @@ class FeatureTransformer { { auto accTilePsqt = reinterpret_cast( &accumulator.psqtAccumulation[Perspective][j * PsqtTileHeight]); - auto entryTilePsqt = reinterpret_cast( - &entry.psqtAccumulation[j * PsqtTileHeight]); - + auto entryTilePsqt = + reinterpret_cast(&entry.psqtAccumulation[j * PsqtTileHeight]); + for (std::size_t k = 0; k < NumPsqtRegs; ++k) psqt[k] = entryTilePsqt[k]; diff --git a/src/search.cpp b/src/search.cpp index ae2b1de23..edbb58c62 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -157,7 +157,8 @@ void Search::Worker::start_searching() { return; } - main_manager()->tm.init(limits, rootPos.side_to_move(), rootPos.game_ply(), options); + main_manager()->tm.init(limits, rootPos.side_to_move(), rootPos.game_ply(), options, + main_manager()->originalPly); tt.new_search(); if (rootMoves.empty()) diff --git a/src/search.h b/src/search.h index c824daf93..6e5b22bda 100644 --- a/src/search.h +++ b/src/search.h @@ -210,6 +210,7 @@ class SearchManager: public ISearchManager { Depth depth) const; Stockfish::TimeManagement tm; + int originalPly; int callsCnt; std::atomic_bool ponder; diff --git a/src/thread.cpp b/src/thread.cpp index 9052654ba..8724cb49c 100644 --- a/src/thread.cpp +++ b/src/thread.cpp @@ -167,6 +167,7 @@ void ThreadPool::clear() { main_manager()->callsCnt = 0; main_manager()->bestPreviousScore = VALUE_INFINITE; main_manager()->bestPreviousAverageScore = VALUE_INFINITE; + main_manager()->originalPly = -1; main_manager()->previousTimeReduction = 1.0; main_manager()->tm.clear(); } diff --git a/src/timeman.cpp b/src/timeman.cpp index 4feb329b3..f389e082d 100644 --- a/src/timeman.cpp +++ b/src/timeman.cpp @@ -44,10 +44,8 @@ void TimeManagement::advance_nodes_time(std::int64_t nodes) { // the bounds of time allowed for the current game ply. We currently support: // 1) x basetime (+ z increment) // 2) x moves in y seconds (+ z increment) -void TimeManagement::init(Search::LimitsType& limits, - Color us, - int ply, - const OptionsMap& options) { +void TimeManagement::init( + Search::LimitsType& limits, Color us, int ply, const OptionsMap& options, int& originalPly) { TimePoint npmsec = TimePoint(options["nodestime"]); // If we have no time, we don't need to fully initialize TM. @@ -58,6 +56,9 @@ void TimeManagement::init(Search::LimitsType& limits, if (limits.time[us] == 0) return; + if (originalPly == -1) + originalPly = ply; + TimePoint moveOverhead = TimePoint(options["Move Overhead"]); // optScale is a percentage of available time to use for the current move. @@ -106,6 +107,8 @@ void TimeManagement::init(Search::LimitsType& limits, { // Use extra time with larger increments double optExtra = scaledInc < 500 ? 1.0 : 1.13; + if (ply - originalPly < 2) + optExtra *= 0.95; // Calculate time constants based on current time left. double logTimeInSec = std::log10(scaledTime / 1000.0); diff --git a/src/timeman.h b/src/timeman.h index 1b6bd849a..8f1bb5639 100644 --- a/src/timeman.h +++ b/src/timeman.h @@ -36,7 +36,8 @@ struct LimitsType; // the maximum available time, the game move number, and other parameters. class TimeManagement { public: - void init(Search::LimitsType& limits, Color us, int ply, const OptionsMap& options); + void init( + Search::LimitsType& limits, Color us, int ply, const OptionsMap& options, int& originalPly); TimePoint optimum() const; TimePoint maximum() const; From fa114266fa7ea996c6d2ef12c625547b1aefddc1 Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Mon, 13 May 2024 14:08:19 +0300 Subject: [PATCH 14/44] Add extra bonus for high-depth condition Passed STC: LLR: 2.93 (-2.94,2.94) <0.00,2.00> Total: 54208 W: 14058 L: 13717 D: 26433 Ptnml(0-2): 166, 6277, 13885, 6602, 174 https://tests.stockfishchess.org/tests/view/664136d8f9f4e8fc783c9b82 Passed LTC: LLR: 2.96 (-2.94,2.94) <0.50,2.50> Total: 112548 W: 28492 L: 28018 D: 56038 Ptnml(0-2): 53, 12186, 31318, 12668, 49 https://tests.stockfishchess.org/tests/view/664143fef9f4e8fc783c9bf6 closes https://github.com/official-stockfish/Stockfish/pull/5242 Bench: 1725980 --- src/search.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index edbb58c62..30f718bd7 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -739,7 +739,7 @@ Value Search::Worker::search( // Use static evaluation difference to improve quiet move ordering (~9 Elo) if (((ss - 1)->currentMove).is_ok() && !(ss - 1)->inCheck && !priorCapture) { - int bonus = std::clamp(-12 * int((ss - 1)->staticEval + ss->staticEval), -1749, 1602); + int bonus = std::clamp(-12 * int((ss - 1)->staticEval + ss->staticEval), -1749, 1584); bonus = bonus > 0 ? 2 * bonus : bonus / 2; thisThread->mainHistory[~us][((ss - 1)->currentMove).from_to()] << bonus; if (type_of(pos.piece_on(prevSq)) != PAWN && ((ss - 1)->currentMove).type_of() != PROMOTION) @@ -1328,8 +1328,8 @@ moves_loop: // When in check, search starts here // Bonus for prior countermove that caused the fail low else if (!priorCapture && prevSq != SQ_NONE) { - int bonus = (depth > 5) + (PvNode || cutNode) + ((ss - 1)->statScore < -14323) - + ((ss - 1)->moveCount > 10) + (!ss->inCheck && bestValue <= ss->staticEval - 127) + int bonus = (depth > 4) + (depth > 5) + (PvNode || cutNode) + ((ss - 1)->statScore < -14323) + + ((ss - 1)->moveCount > 10) + (!ss->inCheck && bestValue <= ss->staticEval - 120) + (!(ss - 1)->inCheck && bestValue <= -(ss - 1)->staticEval - 76); update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq, stat_bonus(depth) * bonus); From 9e45644c50e4650e4603ddef3e8147a8daf3a790 Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Tue, 14 May 2024 20:10:01 +0300 Subject: [PATCH 15/44] Add extra bonus to pawn history for a move that caused a fail low Basically the same idea as it is for continuation/main history, but it has some tweaks. 1) it has * 2 multiplier for bonus instead of full/half bonus - for whatever reason this seems to work better; 2) attempts with this type of big bonuses scaled somewhat poorly (or were unlucky at longer time controls), but after measuring the fact that average value of pawn history in LMR after adding this bonuses increased by substantial number (for multiplier 1,5 it increased by smth like 400~ from 8192 cap) attempts were made to make default pawn history negative to compensate it - and version with multiplier 2 and initial fill value -900 passed. Passed STC: https://tests.stockfishchess.org/tests/view/66424815f9f4e8fc783cba59 LLR: 2.93 (-2.94,2.94) <0.00,2.00> Total: 115008 W: 30001 L: 29564 D: 55443 Ptnml(0-2): 432, 13629, 28903, 14150, 390 Passed LTC: https://tests.stockfishchess.org/tests/view/6642f5437134c82f3f7a3ffa LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 56448 W: 14432 L: 14067 D: 27949 Ptnml(0-2): 36, 6268, 15254, 6627, 39 Bench: 1857237 --- src/search.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 30f718bd7..09a9cc920 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -496,7 +496,7 @@ void Search::Worker::clear() { counterMoves.fill(Move::none()); mainHistory.fill(0); captureHistory.fill(0); - pawnHistory.fill(0); + pawnHistory.fill(-900); correctionHistory.fill(0); for (bool inCheck : {false, true}) @@ -1335,6 +1335,11 @@ moves_loop: // When in check, search starts here stat_bonus(depth) * bonus); thisThread->mainHistory[~us][((ss - 1)->currentMove).from_to()] << stat_bonus(depth) * bonus / 2; + + + if (type_of(pos.piece_on(prevSq)) != PAWN && ((ss - 1)->currentMove).type_of() != PROMOTION) + thisThread->pawnHistory[pawn_structure_index(pos)][pos.piece_on(prevSq)][prevSq] + << stat_bonus(depth) * bonus * 2; } if (PvNode) From 09dba1f0806a973d1f9f4ebf04b7a45d81683168 Mon Sep 17 00:00:00 2001 From: mstembera Date: Mon, 13 May 2024 15:28:48 -0700 Subject: [PATCH 16/44] Call adjustEval with correct parameters after rescore Set smallNet to false after rescoring so we call adjustEval() w/ correct parameters. STC: https://tests.stockfishchess.org/tests/view/664308687134c82f3f7a4003 LLR: 2.93 (-2.94,2.94) <-1.75,0.25> Total: 146912 W: 37856 L: 37756 D: 71300 Ptnml(0-2): 566, 17562, 37122, 17618, 588 LTC: https://tests.stockfishchess.org/tests/view/6643a0821f32a966da7485d6 LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 390414 W: 98015 L: 98173 D: 194226 Ptnml(0-2): 162, 43555, 107929, 43401, 160 closes https://github.com/official-stockfish/Stockfish/pull/5244 Bench: 1819318 --- src/evaluate.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index b5f28d5ae..de1adc989 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -63,7 +63,10 @@ Value Eval::evaluate(const Eval::NNUE::Networks& networks, : networks.big.evaluate(pos, &caches.big, true, &nnueComplexity); if (smallNet && (nnue * simpleEval < 0 || std::abs(nnue) < 500)) - nnue = networks.big.evaluate(pos, &caches.big, true, &nnueComplexity); + { + nnue = networks.big.evaluate(pos, &caches.big, true, &nnueComplexity); + smallNet = false; + } const auto adjustEval = [&](int nnueDiv, int pawnCountMul, int evalDiv, int shufflingConstant) { // Blend optimism and eval with nnue complexity and material imbalance From 9b90cd88f0ddd568e43161a0ada7daf02fc59c67 Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Wed, 15 May 2024 04:10:58 +0200 Subject: [PATCH 17/44] Reduce more when improving and ttvalue is lower than alpha More reduction if position is improving but value from TT doesn't exceeds alpha but the tt move is excluded. This idea is based on following LMR condition tuning https://tests.stockfishchess.org/tests/view/66423a1bf9f4e8fc783cba37 by using only three of the four largest terms P[3], P[18] and P[12]. Passed STC: LLR: 2.93 (-2.94,2.94) <0.00,2.00> Total: 27840 W: 7309 L: 7004 D: 13527 Ptnml(0-2): 85, 3219, 7018, 3502, 96 https://tests.stockfishchess.org/tests/view/6643dc1cbc537f56194508ba Passed LTC: LLR: 2.95 (-2.94,2.94) <0.50,2.50> Total: 191280 W: 48656 L: 48020 D: 94604 Ptnml(0-2): 78, 20979, 52903, 21589, 91 https://tests.stockfishchess.org/tests/view/6643e543bc537f5619451683 closes https://github.com/official-stockfish/Stockfish/pull/5245 Bench: 1430835 --- src/search.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/search.cpp b/src/search.cpp index 09a9cc920..2dadd0dca 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1134,6 +1134,9 @@ moves_loop: // When in check, search starts here if (PvNode) r--; + if (improving && ttValue <= alpha && move != ttMove) + r++; + // Increase reduction if next ply has a lot of fail high (~5 Elo) if ((ss + 1)->cutoffCnt > 3) r++; From 1f3a0fda2e3a0d4aa825dd148c2593fb3631bf82 Mon Sep 17 00:00:00 2001 From: Linmiao Xu Date: Mon, 13 May 2024 18:06:38 -0400 Subject: [PATCH 18/44] Use same eval divisor for both nets Passed non-regression STC: https://tests.stockfishchess.org/tests/view/66428f146577e9d2c8a29cf8 LLR: 2.95 (-2.94,2.94) <-1.75,0.25> Total: 241024 W: 62173 L: 62177 D: 116674 Ptnml(0-2): 904, 28648, 61407, 28654, 899 Passed non-regression LTC: https://tests.stockfishchess.org/tests/view/6643ae6f1f32a966da74977b LLR: 2.95 (-2.94,2.94) <-1.75,0.25> Total: 193710 W: 48762 L: 48717 D: 96231 Ptnml(0-2): 70, 21599, 53481, 21626, 79 closes https://github.com/official-stockfish/Stockfish/pull/5246 Bench: 1700680 --- src/evaluate.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index de1adc989..76d630dd9 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -68,14 +68,13 @@ Value Eval::evaluate(const Eval::NNUE::Networks& networks, smallNet = false; } - const auto adjustEval = [&](int nnueDiv, int pawnCountMul, int evalDiv, int shufflingConstant) { + const auto adjustEval = [&](int nnueDiv, int pawnCountMul, int shufflingConstant) { // Blend optimism and eval with nnue complexity and material imbalance optimism += optimism * (nnueComplexity + std::abs(simpleEval - nnue)) / 584; nnue -= nnue * (nnueComplexity * 5 / 3) / nnueDiv; int npm = pos.non_pawn_material() / 64; - v = (nnue * (npm + 943 + pawnCountMul * pos.count()) + optimism * (npm + 140)) - / evalDiv; + v = (nnue * (npm + 943 + pawnCountMul * pos.count()) + optimism * (npm + 140)) / 1058; // Damp down the evaluation linearly when shuffling int shuffling = pos.rule50_count(); @@ -83,9 +82,9 @@ Value Eval::evaluate(const Eval::NNUE::Networks& networks, }; if (!smallNet) - adjustEval(32395, 11, 1058, 178); + adjustEval(32395, 11, 178); else - adjustEval(32793, 9, 1067, 206); + adjustEval(32793, 9, 206); // 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 dcb02337844d71e56df57b9a8ba17646f953711c Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Wed, 15 May 2024 14:22:36 +0300 Subject: [PATCH 19/44] Simplifying improving and worsening deduction formulas Passed STC: LLR: 2.93 (-2.94,2.94) <-1.75,0.25> Total: 77696 W: 20052 L: 19878 D: 37766 Ptnml(0-2): 222, 9124, 19994, 9274, 234 https://tests.stockfishchess.org/tests/view/66440032bc537f561945171e Passed LTC: LLR: 2.95 (-2.94,2.94) <-1.75,0.25> Total: 234414 W: 58874 L: 58871 D: 116669 Ptnml(0-2): 96, 26147, 64742, 26102, 120 https://tests.stockfishchess.org/tests/view/6644094cbc537f5619451735 closes https://github.com/official-stockfish/Stockfish/pull/5248 Bench: 1336738 --- src/search.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 2dadd0dca..d9041c66a 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -60,8 +60,8 @@ static constexpr double EvalLevel[10] = {0.981, 0.956, 0.895, 0.949, 0.913, // Futility margin Value futility_margin(Depth d, bool noTtCutNode, bool improving, bool oppWorsening) { Value futilityMult = 131 - 48 * noTtCutNode; - Value improvingDeduction = 57 * improving * futilityMult / 32; - Value worseningDeduction = (309 + 52 * improving) * oppWorsening * futilityMult / 1024; + Value improvingDeduction = 2 * improving * futilityMult; + Value worseningDeduction = 330 * oppWorsening * futilityMult / 1024; return futilityMult * d - improvingDeduction - worseningDeduction; } From 541406ab9151891b3a42f49030a6167cfca55599 Mon Sep 17 00:00:00 2001 From: Linmiao Xu Date: Tue, 14 May 2024 16:51:02 -0400 Subject: [PATCH 20/44] Use same nnue divisor for both nets Passed non-regression STC: https://tests.stockfishchess.org/tests/view/6643ceeabc537f56194506f6 LLR: 2.95 (-2.94,2.94) <-1.75,0.25> Total: 224800 W: 57910 L: 57896 D: 108994 Ptnml(0-2): 673, 26790, 57519, 26686, 732 Passed non-regression LTC: https://tests.stockfishchess.org/tests/view/6643ff15bc537f5619451719 LLR: 2.95 (-2.94,2.94) <-1.75,0.25> Total: 347658 W: 87574 L: 87688 D: 172396 Ptnml(0-2): 207, 39004, 95488, 38956, 174 closes https://github.com/official-stockfish/Stockfish/pull/5250 Bench: 1804704 --- src/evaluate.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 76d630dd9..3ce148627 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -68,10 +68,10 @@ Value Eval::evaluate(const Eval::NNUE::Networks& networks, smallNet = false; } - const auto adjustEval = [&](int nnueDiv, int pawnCountMul, int shufflingConstant) { + const auto adjustEval = [&](int pawnCountMul, int shufflingConstant) { // Blend optimism and eval with nnue complexity and material imbalance optimism += optimism * (nnueComplexity + std::abs(simpleEval - nnue)) / 584; - nnue -= nnue * (nnueComplexity * 5 / 3) / nnueDiv; + nnue -= nnue * (nnueComplexity * 5 / 3) / 32395; int npm = pos.non_pawn_material() / 64; v = (nnue * (npm + 943 + pawnCountMul * pos.count()) + optimism * (npm + 140)) / 1058; @@ -82,9 +82,9 @@ Value Eval::evaluate(const Eval::NNUE::Networks& networks, }; if (!smallNet) - adjustEval(32395, 11, 178); + adjustEval(11, 178); else - adjustEval(32793, 9, 206); + adjustEval(9, 206); // 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 e3c9ed77aa62e096d52bb558193279b804f53a84 Mon Sep 17 00:00:00 2001 From: Muzhen Gaming <61100393+XInTheDark@users.noreply.github.com> Date: Wed, 15 May 2024 22:32:55 +0800 Subject: [PATCH 21/44] Revert "Reduce more when improving and ttvalue is lower than alpha" The patch regressed significantly at longer time controls. Passed VLTC: https://tests.stockfishchess.org/tests/view/6644c7a2bc537f5619453096 LLR: 2.95 (-2.94,2.94) <0.00,2.00> Total: 43336 W: 11177 L: 10884 D: 21275 Ptnml(0-2): 3, 4432, 12507, 4721, 5 Passed VVLTC: https://tests.stockfishchess.org/tests/view/66450c974aa4fa9a83b6d0b0 LLR: 2.95 (-2.94,2.94) <0.50,2.50> Total: 32394 W: 8350 L: 8072 D: 15972 Ptnml(0-2): 2, 2798, 10317, 3080, 0 closes https://github.com/official-stockfish/Stockfish/pull/5251 Bench: 1594188 --- src/search.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index d9041c66a..bdcecd1c2 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1134,9 +1134,6 @@ moves_loop: // When in check, search starts here if (PvNode) r--; - if (improving && ttValue <= alpha && move != ttMove) - r++; - // Increase reduction if next ply has a lot of fail high (~5 Elo) if ((ss + 1)->cutoffCnt > 3) r++; From 47597641dc8da7c65d0f1d987f784af09d6aec15 Mon Sep 17 00:00:00 2001 From: Linmiao Xu Date: Wed, 15 May 2024 13:22:46 -0400 Subject: [PATCH 22/44] Lower smallnet threshold linearly as pawn count decreases Passed STC: https://tests.stockfishchess.org/tests/view/6644f677324e96f42f89d894 LLR: 2.94 (-2.94,2.94) <0.00,2.00> Total: 377920 W: 97135 L: 96322 D: 184463 Ptnml(0-2): 1044, 44259, 97588, 44978, 1091 Passed LTC: https://tests.stockfishchess.org/tests/view/664548af93ce6da3e93b31b3 LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 169056 W: 42901 L: 42312 D: 83843 Ptnml(0-2): 58, 18538, 46753, 19115, 64 closes https://github.com/official-stockfish/Stockfish/pull/5252 Bench: 1991750 --- src/evaluate.cpp | 2 +- src/evaluate.h | 2 +- src/nnue/nnue_misc.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 3ce148627..498ec161b 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -55,7 +55,7 @@ Value Eval::evaluate(const Eval::NNUE::Networks& networks, assert(!pos.checkers()); int simpleEval = simple_eval(pos, pos.side_to_move()); - bool smallNet = std::abs(simpleEval) > SmallNetThreshold; + bool smallNet = std::abs(simpleEval) > SmallNetThreshold + 6 * pos.count(); int nnueComplexity; int v; diff --git a/src/evaluate.h b/src/evaluate.h index afaf35ebe..6612ec9da 100644 --- a/src/evaluate.h +++ b/src/evaluate.h @@ -29,7 +29,7 @@ class Position; namespace Eval { -constexpr inline int SmallNetThreshold = 1174; +constexpr inline int SmallNetThreshold = 1126; // 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 diff --git a/src/nnue/nnue_misc.cpp b/src/nnue/nnue_misc.cpp index bf73a58bf..8a7779120 100644 --- a/src/nnue/nnue_misc.cpp +++ b/src/nnue/nnue_misc.cpp @@ -47,7 +47,7 @@ void hint_common_parent_position(const Position& pos, AccumulatorCaches& caches) { int simpleEvalAbs = std::abs(simple_eval(pos, pos.side_to_move())); - if (simpleEvalAbs > Eval::SmallNetThreshold) + if (simpleEvalAbs > Eval::SmallNetThreshold + 6 * pos.count()) networks.small.hint_common_access(pos, &caches.small); else networks.big.hint_common_access(pos, &caches.big); From e0227a627288c786fdd3b12452303ff4eabba5b0 Mon Sep 17 00:00:00 2001 From: Rak Laptudirm Date: Wed, 15 May 2024 22:26:12 +0530 Subject: [PATCH 23/44] Improve comment closes https://github.com/official-stockfish/Stockfish/pull/5249 No functional change --- src/tt.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/tt.cpp b/src/tt.cpp index 4885a781a..cb46fc8a9 100644 --- a/src/tt.cpp +++ b/src/tt.cpp @@ -35,7 +35,7 @@ namespace Stockfish { void TTEntry::save( Key k, Value v, bool pv, Bound b, Depth d, Move m, Value ev, uint8_t generation8) { - // Preserve any existing move for the same position + // Preserve the old ttmove if we don't have a new one if (m || uint16_t(k) != key16) move16 = m; From 1b7dea3f851cd5c5411ba6f07a2f935bfb7da8a9 Mon Sep 17 00:00:00 2001 From: Linmiao Xu Date: Wed, 15 May 2024 19:26:48 -0400 Subject: [PATCH 24/44] Update default main net to nn-c721dfca8cd3.nnue Created by first retraining the spsa-tuned main net `nn-ae6a388e4a1a.nnue` with: - using v6-dd data without bestmove captures removed - addition of T80 mar2024 data - increasing loss by 20% when Q is too high - torch.compile changes for marginal training speed gains And then SPSA tuning weights of epoch 899 following methods described in: https://github.com/official-stockfish/Stockfish/pull/5149 This net was reached at 92k out of 120k steps in this 70+0.7 th 7 SPSA tuning run: https://tests.stockfishchess.org/tests/view/66413b7df9f4e8fc783c9bbb Thanks to @Viren6 for suggesting usage of: - c value 4 for the weights - c value 128 for the biases Scripts for automating applying fishtest spsa params to exporting tuned .nnue are in: https://github.com/linrock/nnue-tools/tree/master/spsa Before spsa tuning, epoch 899 was nn-f85738aefa84.nnue https://tests.stockfishchess.org/tests/view/663e5c893a2f9702074bc167 After initially training with max-epoch 800, training was resumed with max-epoch 1000. ``` experiment-name: 3072--S11--more-data-v6-dd-t80-mar2024--see-ge0-20p-more-loss-high-q-sk28-l8 nnue-pytorch-branch: linrock/nnue-pytorch/3072-r21-skip-more-wdl-see-ge0-20p-more-loss-high-q-torch-compile-more start-from-engine-test-net: False start-from-model: /data/config/apr2024-3072/nn-ae6a388e4a1a.nnue early-fen-skipping: 28 training-dataset: /data/S11-mar2024/: - leela96.v2.min.binpack - test60-2021-11-12-novdec-12tb7p.v6-dd.min.binpack - test78-2022-01-to-05-jantomay-16tb7p.v6-dd.min.binpack - test80-2022-06-jun-16tb7p.v6-dd.min.binpack - test80-2022-08-aug-16tb7p.v6-dd.min.binpack - test80-2022-09-sep-16tb7p.v6-dd.min.binpack - test80-2023-01-jan-16tb7p.v6-sk20.min.binpack - test80-2023-02-feb-16tb7p.v6-sk20.min.binpack - test80-2023-03-mar-2tb7p.v6-sk16.min.binpack - test80-2023-04-apr-2tb7p.v6-sk16.min.binpack - test80-2023-05-may-2tb7p.v6.min.binpack # https://github.com/official-stockfish/Stockfish/pull/4782 - test80-2023-06-jun-2tb7p.binpack - test80-2023-07-jul-2tb7p.binpack # https://github.com/official-stockfish/Stockfish/pull/4972 - test80-2023-08-aug-2tb7p.v6.min.binpack - test80-2023-09-sep-2tb7p.binpack - test80-2023-10-oct-2tb7p.binpack # S9 new data: https://github.com/official-stockfish/Stockfish/pull/5056 - test80-2023-11-nov-2tb7p.binpack - test80-2023-12-dec-2tb7p.binpack # S10 new data: https://github.com/official-stockfish/Stockfish/pull/5149 - test80-2024-01-jan-2tb7p.binpack - test80-2024-02-feb-2tb7p.binpack # S11 new data - test80-2024-03-mar-2tb7p.binpack /data/filt-v6-dd/: - test77-dec2021-16tb7p-filter-v6-dd.binpack - test78-juntosep2022-16tb7p-filter-v6-dd.binpack - test79-apr2022-16tb7p-filter-v6-dd.binpack - test79-may2022-16tb7p-filter-v6-dd.binpack - test80-jul2022-16tb7p-filter-v6-dd.binpack - test80-oct2022-16tb7p-filter-v6-dd.binpack - test80-nov2022-16tb7p-filter-v6-dd.binpack num-epochs: 1000 lr: 4.375e-4 gamma: 0.995 start-lambda: 0.8 end-lambda: 0.7 ``` Training data can be found at: https://robotmoon.com/nnue-training-data/ Local elo at 25k nodes per move: nn-epoch899.nnue : 4.6 +/- 1.4 Passed STC: https://tests.stockfishchess.org/tests/view/6645454893ce6da3e93b31ae LLR: 2.95 (-2.94,2.94) <0.00,2.00> Total: 95232 W: 24598 L: 24194 D: 46440 Ptnml(0-2): 294, 11215, 24180, 11647, 280 Passed LTC: https://tests.stockfishchess.org/tests/view/6645522d93ce6da3e93b31df LLR: 2.95 (-2.94,2.94) <0.50,2.50> Total: 320544 W: 81432 L: 80524 D: 158588 Ptnml(0-2): 164, 35659, 87696, 36611, 142 closes https://github.com/official-stockfish/Stockfish/pull/5254 bench 1995552 --- src/evaluate.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/evaluate.h b/src/evaluate.h index 6612ec9da..c87be53c1 100644 --- a/src/evaluate.h +++ b/src/evaluate.h @@ -35,7 +35,7 @@ constexpr inline int SmallNetThreshold = 1126; // for the build process (profile-build and fishtest) to work. Do not change the // name of the macro or the location where this macro is defined, as it is used // in the Makefile/Fishtest. -#define EvalFileDefaultNameBig "nn-ae6a388e4a1a.nnue" +#define EvalFileDefaultNameBig "nn-c721dfca8cd3.nnue" #define EvalFileDefaultNameSmall "nn-baff1ede1f90.nnue" namespace NNUE { From d92d1f31809afc8aa83cc14fcbd54b95258d09ad Mon Sep 17 00:00:00 2001 From: Linmiao Xu Date: Thu, 16 May 2024 01:48:56 -0400 Subject: [PATCH 25/44] Move smallnet threshold logic into a function Now that the smallnet threshold is no longer a constant, use a function to organize it with other eval code. Passed non-regression STC: https://tests.stockfishchess.org/tests/view/66459fa093ce6da3e93b5ba2 LLR: 2.95 (-2.94,2.94) <-1.75,0.25> Total: 217600 W: 56281 L: 56260 D: 105059 Ptnml(0-2): 756, 23787, 59729, 23736, 792 closes https://github.com/official-stockfish/Stockfish/pull/5255 No functional change --- src/evaluate.cpp | 6 +++++- src/evaluate.h | 3 +-- src/nnue/nnue_misc.cpp | 4 +--- 3 files changed, 7 insertions(+), 6 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 498ec161b..09402b8b1 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -44,6 +44,10 @@ int Eval::simple_eval(const Position& pos, Color c) { + (pos.non_pawn_material(c) - pos.non_pawn_material(~c)); } +bool Eval::use_smallnet(const Position& pos) { + int simpleEval = simple_eval(pos, pos.side_to_move()); + return std::abs(simpleEval) > 1126 + 6 * pos.count(); +} // Evaluate is the evaluator for the outer world. It returns a static evaluation // of the position from the point of view of the side to move. @@ -55,7 +59,7 @@ Value Eval::evaluate(const Eval::NNUE::Networks& networks, assert(!pos.checkers()); int simpleEval = simple_eval(pos, pos.side_to_move()); - bool smallNet = std::abs(simpleEval) > SmallNetThreshold + 6 * pos.count(); + bool smallNet = use_smallnet(pos); int nnueComplexity; int v; diff --git a/src/evaluate.h b/src/evaluate.h index c87be53c1..4b3e91acf 100644 --- a/src/evaluate.h +++ b/src/evaluate.h @@ -29,8 +29,6 @@ class Position; namespace Eval { -constexpr inline int SmallNetThreshold = 1126; - // 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 or the location where this macro is defined, as it is used @@ -46,6 +44,7 @@ struct AccumulatorCaches; std::string trace(Position& pos, const Eval::NNUE::Networks& networks); int simple_eval(const Position& pos, Color c); +bool use_smallnet(const Position& pos); Value evaluate(const NNUE::Networks& networks, const Position& pos, Eval::NNUE::AccumulatorCaches& caches, diff --git a/src/nnue/nnue_misc.cpp b/src/nnue/nnue_misc.cpp index 8a7779120..a13c717c3 100644 --- a/src/nnue/nnue_misc.cpp +++ b/src/nnue/nnue_misc.cpp @@ -45,9 +45,7 @@ constexpr std::string_view PieceToChar(" PNBRQK pnbrqk"); void hint_common_parent_position(const Position& pos, const Networks& networks, AccumulatorCaches& caches) { - - int simpleEvalAbs = std::abs(simple_eval(pos, pos.side_to_move())); - if (simpleEvalAbs > Eval::SmallNetThreshold + 6 * pos.count()) + if (Eval::use_smallnet(pos)) networks.small.hint_common_access(pos, &caches.small); else networks.big.hint_common_access(pos, &caches.big); From f5e15441b8e3b8087024d309313e8a4d6c48bba7 Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Sat, 18 May 2024 01:22:41 +0300 Subject: [PATCH 26/44] Early Exit in Bitboards::sliding_attack() he original code checks for occupancy within the loop condition. By moving this check inside the loop and adding an early exit condition, we can avoid unnecessary iterations if a blocking piece is encountered. Passed stc: LLR: 2.95 (-2.94,2.94) <0.00,2.00> Total: 127200 W: 33129 L: 32700 D: 61371 Ptnml(0-2): 424, 13243, 35826, 13694, 413 https://tests.stockfishchess.org/tests/view/664646006dcff0d1d6b05bca closes https://github.com/official-stockfish/Stockfish/pull/5256 No functional change --- src/bitboard.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/bitboard.cpp b/src/bitboard.cpp index 32c626d47..c842ca127 100644 --- a/src/bitboard.cpp +++ b/src/bitboard.cpp @@ -124,8 +124,14 @@ Bitboard sliding_attack(PieceType pt, Square sq, Bitboard occupied) { for (Direction d : (pt == ROOK ? RookDirections : BishopDirections)) { Square s = sq; - while (safe_destination(s, d) && !(occupied & s)) + while (safe_destination(s, d)) + { attacks |= (s += d); + if (occupied & s) + { + break; + } + } } return attacks; From 285f1d2a663fb111f7124272403923eab4251982 Mon Sep 17 00:00:00 2001 From: Shawn Xu Date: Wed, 15 May 2024 22:26:15 -0700 Subject: [PATCH 27/44] Tweak NMP Formula Passed STC: LLR: 2.99 (-2.94,2.94) <0.00,2.00> Total: 241728 W: 62440 L: 61811 D: 117477 Ptnml(0-2): 914, 28467, 61458, 29126, 899 https://tests.stockfishchess.org/tests/live_elo/6645992993ce6da3e93b5b99 Passed LTC: LLR: 2.96 (-2.94,2.94) <0.50,2.50> Total: 167850 W: 42620 L: 42030 D: 83200 Ptnml(0-2): 82, 18412, 46354, 18988, 89 https://tests.stockfishchess.org/tests/live_elo/6647c5726dcff0d1d6b05dd3 closes https://github.com/official-stockfish/Stockfish/pull/5257 Bench: 1636018 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index bdcecd1c2..06c6e1987 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -787,7 +787,7 @@ Value Search::Worker::search( assert(eval - beta >= 0); // Null move dynamic reduction based on depth and eval - Depth R = std::min(int(eval - beta) / 144, 6) + depth / 3 + 4; + Depth R = std::min(int(eval - beta) / 144, 6) + depth / 3 + 5; ss->currentMove = Move::null(); ss->continuationHistory = &thisThread->continuationHistory[0][0][NO_PIECE][0]; From 99dfc63e0321cb8544ce5455993df00a6c817ba3 Mon Sep 17 00:00:00 2001 From: Linmiao Xu Date: Fri, 17 May 2024 19:27:20 -0400 Subject: [PATCH 28/44] Use one nnue pawn count multiplier Switch to the value used by the main net. Passed non-regression STC: https://tests.stockfishchess.org/tests/view/6647e8096dcff0d1d6b05e96 LLR: 2.93 (-2.94,2.94) <-1.75,0.25> Total: 51040 W: 13249 L: 13044 D: 24747 Ptnml(0-2): 139, 6029, 13016, 6160, 176 Passed non-regression LTC: https://tests.stockfishchess.org/tests/view/6647f4a46dcff0d1d6b05eea LLR: 2.95 (-2.94,2.94) <-1.75,0.25> Total: 20460 W: 5195 L: 4972 D: 10293 Ptnml(0-2): 8, 2178, 5637, 2397, 10 https://github.com/official-stockfish/Stockfish/pull/5258 bench 1887462 --- src/evaluate.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 09402b8b1..abb04fcc2 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -72,13 +72,13 @@ Value Eval::evaluate(const Eval::NNUE::Networks& networks, smallNet = false; } - const auto adjustEval = [&](int pawnCountMul, int shufflingConstant) { + const auto adjustEval = [&](int shufflingConstant) { // Blend optimism and eval with nnue complexity and material imbalance optimism += optimism * (nnueComplexity + std::abs(simpleEval - nnue)) / 584; nnue -= nnue * (nnueComplexity * 5 / 3) / 32395; int npm = pos.non_pawn_material() / 64; - v = (nnue * (npm + 943 + pawnCountMul * pos.count()) + optimism * (npm + 140)) / 1058; + v = (nnue * (npm + 943 + 11 * pos.count()) + optimism * (npm + 140)) / 1058; // Damp down the evaluation linearly when shuffling int shuffling = pos.rule50_count(); @@ -86,9 +86,9 @@ Value Eval::evaluate(const Eval::NNUE::Networks& networks, }; if (!smallNet) - adjustEval(11, 178); + adjustEval(178); else - adjustEval(9, 206); + adjustEval(206); // 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 4edd1a389e4146a610098a841841f37f58980213 Mon Sep 17 00:00:00 2001 From: Shawn Xu Date: Fri, 17 May 2024 17:45:09 -0700 Subject: [PATCH 29/44] Simplify Away Quadruple Extensions serendipitous gainer Passed LTC: LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 95472 W: 24176 L: 24031 D: 47265 Ptnml(0-2): 52, 10533, 26414, 10692, 45 https://tests.stockfishchess.org/tests/live_elo/6647fa596dcff0d1d6b05efa Passed VVLTC 70+7 th 7: LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 6772 W: 1793 L: 1583 D: 3396 Ptnml(0-2): 0, 502, 2172, 712, 0 https://tests.stockfishchess.org/tests/live_elo/6648277a6dcff0d1d6b05ffb Passed VVLTC 70+7 th 7 (2x): https://tests.stockfishchess.org/tests/view/66484c896dcff0d1d6b0619d LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 5424 W: 1469 L: 1254 D: 2701 Ptnml(0-2): 0, 394, 1710, 607, 1 closes https://github.com/official-stockfish/Stockfish/pull/5259 Bench: 1441794 --- src/search.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 06c6e1987..2b95043fd 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1053,11 +1053,9 @@ moves_loop: // When in check, search starts here int doubleMargin = 285 * PvNode - 228 * !ttCapture; int tripleMargin = 121 + 238 * PvNode - 259 * !ttCapture + 117 * (ss->ttPv || !ttCapture); - int quadMargin = 471 + 343 * PvNode - 281 * !ttCapture + 217 * ss->ttPv; extension = 1 + (value < singularBeta - doubleMargin) - + (value < singularBeta - tripleMargin) - + (value < singularBeta - quadMargin); + + (value < singularBeta - tripleMargin); depth += ((!PvNode) && (depth < 14)); } From 2694fce928e5eec867d56d853b416c9f389c284d Mon Sep 17 00:00:00 2001 From: Linmiao Xu Date: Fri, 17 May 2024 21:38:38 -0400 Subject: [PATCH 30/44] Simplify away adjustEval lambda Now that only the shuffling constant differs between nets, a lambda for adjusting eval is no longer needed. Passed non-regression STC: https://tests.stockfishchess.org/tests/view/664806ca6dcff0d1d6b05f34 LLR: 2.99 (-2.94,2.94) <-1.75,0.25> Total: 31552 W: 8175 L: 7959 D: 15418 Ptnml(0-2): 76, 3180, 9065, 3362, 93 closes https://github.com/official-stockfish/Stockfish/pull/5260 No functional change --- src/evaluate.cpp | 22 +++++++--------------- 1 file changed, 7 insertions(+), 15 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index abb04fcc2..e5ebd45ae 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -72,23 +72,15 @@ Value Eval::evaluate(const Eval::NNUE::Networks& networks, smallNet = false; } - const auto adjustEval = [&](int shufflingConstant) { - // Blend optimism and eval with nnue complexity and material imbalance - optimism += optimism * (nnueComplexity + std::abs(simpleEval - nnue)) / 584; - nnue -= nnue * (nnueComplexity * 5 / 3) / 32395; + // Blend optimism and eval with nnue complexity and material imbalance + optimism += optimism * (nnueComplexity + std::abs(simpleEval - nnue)) / 584; + nnue -= nnue * (nnueComplexity * 5 / 3) / 32395; - int npm = pos.non_pawn_material() / 64; - v = (nnue * (npm + 943 + 11 * pos.count()) + optimism * (npm + 140)) / 1058; + int npm = pos.non_pawn_material() / 64; + v = (nnue * (npm + 943 + 11 * pos.count()) + optimism * (npm + 140)) / 1058; - // Damp down the evaluation linearly when shuffling - int shuffling = pos.rule50_count(); - v = v * (shufflingConstant - shuffling) / 207; - }; - - if (!smallNet) - adjustEval(178); - else - adjustEval(206); + // Damp down the evaluation linearly when shuffling + v = v * ((smallNet ? 206 : 178) - 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 99f1bacfd6864afca86ae74f33232b9cdfb3828c Mon Sep 17 00:00:00 2001 From: Muzhen Gaming <61100393+XInTheDark@users.noreply.github.com> Date: Sat, 18 May 2024 22:15:41 +0800 Subject: [PATCH 31/44] VVLTC search tune Tuned with 85k games at VVLTC. VVLTC 1st sprt: https://tests.stockfishchess.org/tests/view/6648b836308cceea45533ad7 LLR: 2.94 (-2.94,2.94) <0.00,2.00> Total: 14880 W: 3890 L: 3652 D: 7338 Ptnml(0-2): 0, 1255, 4694, 1489, 2 VVLTC 2nd sprt: https://tests.stockfishchess.org/tests/view/6648c34f308cceea45533b4f LLR: 2.95 (-2.94,2.94) <0.50,2.50> Total: 24984 W: 6502 L: 6235 D: 12247 Ptnml(0-2): 1, 2178, 7867, 2445, 1 closes https://github.com/official-stockfish/Stockfish/pull/5264 Bench: 1198142 --- src/search.cpp | 84 +++++++++++++++++++++++++------------------------- 1 file changed, 42 insertions(+), 42 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 2b95043fd..54990ce6f 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -59,9 +59,9 @@ static constexpr double EvalLevel[10] = {0.981, 0.956, 0.895, 0.949, 0.913, // Futility margin Value futility_margin(Depth d, bool noTtCutNode, bool improving, bool oppWorsening) { - Value futilityMult = 131 - 48 * noTtCutNode; - Value improvingDeduction = 2 * improving * futilityMult; - Value worseningDeduction = 330 * oppWorsening * futilityMult / 1024; + Value futilityMult = 127 - 48 * noTtCutNode; + Value improvingDeduction = 65 * improving * futilityMult / 32; + Value worseningDeduction = 334 * oppWorsening * futilityMult / 1024; return futilityMult * d - improvingDeduction - worseningDeduction; } @@ -73,15 +73,15 @@ constexpr int futility_move_count(bool improving, Depth depth) { // Add correctionHistory value to raw staticEval and guarantee evaluation does not hit the tablebase range Value to_corrected_static_eval(Value v, const Worker& w, const Position& pos) { auto cv = w.correctionHistory[pos.side_to_move()][pawn_structure_index(pos)]; - v += cv * std::abs(cv) / 7179; + v += cv * std::abs(cv) / 6047; return std::clamp(v, VALUE_TB_LOSS_IN_MAX_PLY + 1, VALUE_TB_WIN_IN_MAX_PLY - 1); } // History and stats update bonus, based on depth -int stat_bonus(Depth d) { return std::clamp(200 * d - 280, 16, 1495); } +int stat_bonus(Depth d) { return std::clamp(187 * d - 288, 17, 1548); } // History and stats update malus, based on depth -int stat_malus(Depth d) { return (d < 4 ? 586 * d - 284 : 1639); } +int stat_malus(Depth d) { return (d < 4 ? 630 * d - 281 : 1741); } // Add a small random component to draw evaluations to avoid 3-fold blindness Value value_draw(size_t nodes) { return VALUE_DRAW - 1 + Value(nodes & 0x2); } @@ -311,12 +311,12 @@ void Search::Worker::iterative_deepening() { // Reset aspiration window starting size Value avg = rootMoves[pvIdx].averageScore; - delta = 10 + avg * avg / 9474; + delta = 10 + avg * avg / 9828; alpha = std::max(avg - delta, -VALUE_INFINITE); beta = std::min(avg + delta, VALUE_INFINITE); // Adjust optimism based on root move's averageScore (~4 Elo) - optimism[us] = 117 * avg / (std::abs(avg) + 88); + optimism[us] = 116 * avg / (std::abs(avg) + 84); optimism[~us] = -optimism[us]; // Start with a small aspiration window and, in the case of a fail @@ -503,10 +503,10 @@ void Search::Worker::clear() { for (StatsType c : {NoCaptures, Captures}) for (auto& to : continuationHistory[inCheck][c]) for (auto& h : to) - h->fill(-62); + h->fill(-60); for (size_t i = 1; i < reductions.size(); ++i) - reductions[i] = int((21.19 + std::log(size_t(options["Threads"])) / 2) * std::log(i)); + reductions[i] = int((21.69 + std::log(size_t(options["Threads"])) / 2) * std::log(i)); refreshTable.clear(networks); } @@ -739,7 +739,7 @@ Value Search::Worker::search( // Use static evaluation difference to improve quiet move ordering (~9 Elo) if (((ss - 1)->currentMove).is_ok() && !(ss - 1)->inCheck && !priorCapture) { - int bonus = std::clamp(-12 * int((ss - 1)->staticEval + ss->staticEval), -1749, 1584); + int bonus = std::clamp(-11 * int((ss - 1)->staticEval + ss->staticEval), -1729, 1517); bonus = bonus > 0 ? 2 * bonus : bonus / 2; thisThread->mainHistory[~us][((ss - 1)->currentMove).from_to()] << bonus; if (type_of(pos.piece_on(prevSq)) != PAWN && ((ss - 1)->currentMove).type_of() != PROMOTION) @@ -762,7 +762,7 @@ Value Search::Worker::search( // If eval is really low check with qsearch if it can exceed alpha, if it can't, // return a fail low. // Adjust razor margin according to cutoffCnt. (~1 Elo) - if (eval < alpha - 473 - (308 - 138 * ((ss + 1)->cutoffCnt > 3)) * depth * depth) + if (eval < alpha - 474 - (326 - 139 * ((ss + 1)->cutoffCnt > 3)) * depth * depth) { value = qsearch(pos, ss, alpha - 1, alpha); if (value < alpha) @@ -773,21 +773,21 @@ Value Search::Worker::search( // The depth condition is important for mate finding. if (!ss->ttPv && depth < 11 && eval - futility_margin(depth, cutNode && !ss->ttHit, improving, opponentWorsening) - - (ss - 1)->statScore / 258 + - (ss - 1)->statScore / 252 >= beta && eval >= beta && eval < VALUE_TB_WIN_IN_MAX_PLY && (!ttMove || ttCapture)) return beta > VALUE_TB_LOSS_IN_MAX_PLY ? (eval + beta) / 2 : eval; // Step 9. Null move search with verification search (~35 Elo) - if (!PvNode && (ss - 1)->currentMove != Move::null() && (ss - 1)->statScore < 16079 - && eval >= beta && ss->staticEval >= beta - 21 * depth + 324 && !excludedMove + if (!PvNode && (ss - 1)->currentMove != Move::null() && (ss - 1)->statScore < 15246 + && eval >= beta && ss->staticEval >= beta - 21 * depth + 366 && !excludedMove && pos.non_pawn_material(us) && ss->ply >= thisThread->nmpMinPly && beta > VALUE_TB_LOSS_IN_MAX_PLY) { assert(eval - beta >= 0); // Null move dynamic reduction based on depth and eval - Depth R = std::min(int(eval - beta) / 144, 6) + depth / 3 + 5; + Depth R = std::min(int(eval - beta) / 152, 6) + depth / 3 + 5; ss->currentMove = Move::null(); ss->continuationHistory = &thisThread->continuationHistory[0][0][NO_PIECE][0]; @@ -835,7 +835,7 @@ Value Search::Worker::search( // Step 11. ProbCut (~10 Elo) // If we have a good enough capture (or queen promotion) and a reduced search returns a value // much above beta, we can (almost) safely prune the previous move. - probCutBeta = beta + 177 - 65 * improving; + probCutBeta = beta + 176 - 65 * improving; if ( !PvNode && depth > 3 && std::abs(beta) < VALUE_TB_WIN_IN_MAX_PLY @@ -891,7 +891,7 @@ Value Search::Worker::search( moves_loop: // When in check, search starts here // Step 12. A small Probcut idea, when we are in check (~4 Elo) - probCutBeta = beta + 428; + probCutBeta = beta + 440; if (ss->inCheck && !PvNode && ttCapture && (tte->bound() & BOUND_LOWER) && tte->depth() >= depth - 4 && ttValue >= probCutBeta && std::abs(ttValue) < VALUE_TB_WIN_IN_MAX_PLY && std::abs(beta) < VALUE_TB_WIN_IN_MAX_PLY) @@ -975,15 +975,15 @@ moves_loop: // When in check, search starts here // Futility pruning for captures (~2 Elo) if (!givesCheck && lmrDepth < 7 && !ss->inCheck) { - Value futilityValue = ss->staticEval + 305 + 272 * lmrDepth + Value futilityValue = ss->staticEval + 276 + 256 * lmrDepth + PieceValue[capturedPiece] + captHist / 7; if (futilityValue <= alpha) continue; } // SEE based pruning for captures and checks (~11 Elo) - int seeHist = std::clamp(captHist / 32, -185 * depth, 182 * depth); - if (!pos.see_ge(move, -176 * depth - seeHist)) + int seeHist = std::clamp(captHist / 32, -177 * depth, 175 * depth); + if (!pos.see_ge(move, -183 * depth - seeHist)) continue; } else @@ -994,18 +994,18 @@ moves_loop: // When in check, search starts here + thisThread->pawnHistory[pawn_structure_index(pos)][movedPiece][move.to_sq()]; // Continuation history based pruning (~2 Elo) - if (lmrDepth < 6 && history < -4360 * depth) + if (lmrDepth < 6 && history < -4076 * depth) continue; history += 2 * thisThread->mainHistory[us][move.from_to()]; - lmrDepth += history / 4507; + lmrDepth += history / 4401; Value futilityValue = - ss->staticEval + (bestValue < ss->staticEval - 54 ? 142 : 55) + 132 * lmrDepth; + ss->staticEval + (bestValue < ss->staticEval - 53 ? 151 : 57) + 140 * lmrDepth; // Futility pruning: parent node (~13 Elo) - if (!ss->inCheck && lmrDepth < 11 && futilityValue <= alpha) + if (!ss->inCheck && lmrDepth < 10 && futilityValue <= alpha) { if (bestValue <= futilityValue && std::abs(bestValue) < VALUE_TB_WIN_IN_MAX_PLY && futilityValue < VALUE_TB_WIN_IN_MAX_PLY) @@ -1016,7 +1016,7 @@ moves_loop: // When in check, search starts here lmrDepth = std::max(lmrDepth, 0); // Prune moves with negative SEE (~4 Elo) - if (!pos.see_ge(move, -27 * lmrDepth * lmrDepth)) + if (!pos.see_ge(move, -26 * lmrDepth * lmrDepth)) continue; } } @@ -1036,11 +1036,11 @@ moves_loop: // When in check, search starts here // so changing them requires tests at these types of time controls. // Recursive singular search is avoided. if (!rootNode && move == ttMove && !excludedMove - && depth >= 4 - (thisThread->completedDepth > 33) + ss->ttPv + && depth >= 4 - (thisThread->completedDepth > 35) + ss->ttPv && std::abs(ttValue) < VALUE_TB_WIN_IN_MAX_PLY && (tte->bound() & BOUND_LOWER) && tte->depth() >= depth - 3) { - Value singularBeta = ttValue - (59 + 49 * (ss->ttPv && !PvNode)) * depth / 64; + Value singularBeta = ttValue - (57 + 50 * (ss->ttPv && !PvNode)) * depth / 64; Depth singularDepth = newDepth / 2; ss->excludedMove = move; @@ -1050,14 +1050,14 @@ moves_loop: // When in check, search starts here if (value < singularBeta) { - int doubleMargin = 285 * PvNode - 228 * !ttCapture; + int doubleMargin = 298 * PvNode - 209 * !ttCapture; int tripleMargin = - 121 + 238 * PvNode - 259 * !ttCapture + 117 * (ss->ttPv || !ttCapture); + 117 + 252 * PvNode - 270 * !ttCapture + 111 * (ss->ttPv || !ttCapture); extension = 1 + (value < singularBeta - doubleMargin) + (value < singularBeta - tripleMargin); - depth += ((!PvNode) && (depth < 14)); + depth += ((!PvNode) && (depth < 15)); } // Multi-cut pruning @@ -1092,7 +1092,7 @@ moves_loop: // When in check, search starts here else if (PvNode && move == ttMove && move.to_sq() == prevSq && thisThread->captureHistory[movedPiece][move.to_sq()] [type_of(pos.piece_on(move.to_sq()))] - > 4041) + > 3748) extension = 1; } @@ -1143,10 +1143,10 @@ moves_loop: // When in check, search starts here ss->statScore = 2 * thisThread->mainHistory[us][move.from_to()] + (*contHist[0])[movedPiece][move.to_sq()] - + (*contHist[1])[movedPiece][move.to_sq()] - 5313; + + (*contHist[1])[movedPiece][move.to_sq()] - 5266; // Decrease/increase reduction for moves with a good/bad history (~8 Elo) - r -= ss->statScore / (16145 - std::min(depth, 15) * 102); + r -= ss->statScore / (14519 - std::min(depth, 15) * 103); // Step 17. Late moves reduction / extension (LMR, ~117 Elo) if (depth >= 2 && moveCount > 1 + rootNode) @@ -1165,7 +1165,7 @@ moves_loop: // When in check, search starts here { // Adjust full-depth search based on LMR results - if the result // was good enough search deeper, if it was bad enough search shallower. - const bool doDeeperSearch = value > (bestValue + 41 + 2 * newDepth); // (~1 Elo) + const bool doDeeperSearch = value > (bestValue + 40 + 2 * newDepth); // (~1 Elo) const bool doShallowerSearch = value < bestValue + newDepth; // (~2 Elo) newDepth += doDeeperSearch - doShallowerSearch; @@ -1326,9 +1326,9 @@ moves_loop: // When in check, search starts here // Bonus for prior countermove that caused the fail low else if (!priorCapture && prevSq != SQ_NONE) { - int bonus = (depth > 4) + (depth > 5) + (PvNode || cutNode) + ((ss - 1)->statScore < -14323) - + ((ss - 1)->moveCount > 10) + (!ss->inCheck && bestValue <= ss->staticEval - 120) - + (!(ss - 1)->inCheck && bestValue <= -(ss - 1)->staticEval - 76); + int bonus = (depth > 4) + (depth > 5) + (PvNode || cutNode) + ((ss - 1)->statScore < -13241) + + ((ss - 1)->moveCount > 10) + (!ss->inCheck && bestValue <= ss->staticEval - 127) + + (!(ss - 1)->inCheck && bestValue <= -(ss - 1)->staticEval - 74); update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq, stat_bonus(depth) * bonus); thisThread->mainHistory[~us][((ss - 1)->currentMove).from_to()] @@ -1494,7 +1494,7 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta, if (bestValue > alpha) alpha = bestValue; - futilityBase = ss->staticEval + 259; + futilityBase = ss->staticEval + 264; } const PieceToHistory* contHist[] = {(ss - 1)->continuationHistory, @@ -1566,11 +1566,11 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta, + (*contHist[1])[pos.moved_piece(move)][move.to_sq()] + thisThread->pawnHistory[pawn_structure_index(pos)][pos.moved_piece(move)] [move.to_sq()] - <= 4057) + <= 4348) continue; // Do not search moves with bad enough SEE values (~5 Elo) - if (!pos.see_ge(move, -68)) + if (!pos.see_ge(move, -63)) continue; } @@ -1636,7 +1636,7 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth Search::Worker::reduction(bool i, Depth d, int mn, int delta) { int reductionScale = reductions[d] * reductions[mn]; - return (reductionScale + 1284 - delta * 755 / rootDelta) / 1024 + (!i && reductionScale > 1133); + return (reductionScale + 1147 - delta * 755 / rootDelta) / 1024 + (!i && reductionScale > 1125); } // elapsed() returns the time elapsed since the search started. If the From 2d3258162387bf38551962bf2c9dd1d47e72b4dd Mon Sep 17 00:00:00 2001 From: Viren6 <94880762+Viren6@users.noreply.github.com> Date: Sun, 19 May 2024 01:40:29 +0100 Subject: [PATCH 32/44] Revert "Simplify Away Quadruple Extensions" This reverts commit 4edd1a3 The unusual result of (combined) +12.0 +- 3.7 in the 2 VVLTC simplification SPRTs ran was the result of base having only 64MB of hash instead of 512MB (Asymmetric hash). Vizvezdenec was the one to notice this. closes https://github.com/official-stockfish/Stockfish/pull/5265 bench 1404295 Co-Authored-By: Michael Chaly <26898827+Vizvezdenec@users.noreply.github.com> --- src/search.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 54990ce6f..cbd454efb 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1053,9 +1053,11 @@ moves_loop: // When in check, search starts here int doubleMargin = 298 * PvNode - 209 * !ttCapture; int tripleMargin = 117 + 252 * PvNode - 270 * !ttCapture + 111 * (ss->ttPv || !ttCapture); + int quadMargin = 471 + 343 * PvNode - 281 * !ttCapture + 217 * ss->ttPv; extension = 1 + (value < singularBeta - doubleMargin) - + (value < singularBeta - tripleMargin); + + (value < singularBeta - tripleMargin) + + (value < singularBeta - quadMargin); depth += ((!PvNode) && (depth < 15)); } From 27eb49a2211c90650ef64d5102e6e36ca5e69af0 Mon Sep 17 00:00:00 2001 From: cj5716 <125858804+cj5716@users.noreply.github.com> Date: Fri, 17 May 2024 18:05:12 +0800 Subject: [PATCH 33/44] Simplify ClippedReLU Removes some max calls Some speedup stats, courtesy of @AndyGrant (albeit measured in an alternate implementation) Dev 749240 nps Base 748495 nps Gain 0.100% 289936 games STC: LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 203040 W: 52213 L: 52179 D: 98648 Ptnml(0-2): 480, 20722, 59139, 20642, 537 https://tests.stockfishchess.org/tests/view/664805fe6dcff0d1d6b05f2c closes #5261 No functional change --- src/nnue/layers/clipped_relu.h | 48 ++++++++++++++++------------------ src/nnue/nnue_misc.cpp | 9 +++---- src/tune.cpp | 6 ++--- src/uci.cpp | 6 ++--- 4 files changed, 30 insertions(+), 39 deletions(-) diff --git a/src/nnue/layers/clipped_relu.h b/src/nnue/layers/clipped_relu.h index 813234c59..2ee378ad8 100644 --- a/src/nnue/layers/clipped_relu.h +++ b/src/nnue/layers/clipped_relu.h @@ -65,41 +65,37 @@ class ClippedReLU { if constexpr (InputDimensions % SimdWidth == 0) { constexpr IndexType NumChunks = InputDimensions / SimdWidth; - const __m256i Zero = _mm256_setzero_si256(); const __m256i Offsets = _mm256_set_epi32(7, 3, 6, 2, 5, 1, 4, 0); const auto in = reinterpret_cast(input); const auto out = reinterpret_cast<__m256i*>(output); for (IndexType i = 0; i < NumChunks; ++i) { const __m256i words0 = - _mm256_srai_epi16(_mm256_packs_epi32(_mm256_load_si256(&in[i * 4 + 0]), - _mm256_load_si256(&in[i * 4 + 1])), + _mm256_srli_epi16(_mm256_packus_epi32(_mm256_load_si256(&in[i * 4 + 0]), + _mm256_load_si256(&in[i * 4 + 1])), WeightScaleBits); const __m256i words1 = - _mm256_srai_epi16(_mm256_packs_epi32(_mm256_load_si256(&in[i * 4 + 2]), - _mm256_load_si256(&in[i * 4 + 3])), + _mm256_srli_epi16(_mm256_packus_epi32(_mm256_load_si256(&in[i * 4 + 2]), + _mm256_load_si256(&in[i * 4 + 3])), WeightScaleBits); - _mm256_store_si256( - &out[i], _mm256_permutevar8x32_epi32( - _mm256_max_epi8(_mm256_packs_epi16(words0, words1), Zero), Offsets)); + _mm256_store_si256(&out[i], _mm256_permutevar8x32_epi32( + _mm256_packs_epi16(words0, words1), Offsets)); } } else { constexpr IndexType NumChunks = InputDimensions / (SimdWidth / 2); - const __m128i Zero = _mm_setzero_si128(); const auto in = reinterpret_cast(input); const auto out = reinterpret_cast<__m128i*>(output); for (IndexType i = 0; i < NumChunks; ++i) { - const __m128i words0 = _mm_srai_epi16( - _mm_packs_epi32(_mm_load_si128(&in[i * 4 + 0]), _mm_load_si128(&in[i * 4 + 1])), + const __m128i words0 = _mm_srli_epi16( + _mm_packus_epi32(_mm_load_si128(&in[i * 4 + 0]), _mm_load_si128(&in[i * 4 + 1])), WeightScaleBits); - const __m128i words1 = _mm_srai_epi16( - _mm_packs_epi32(_mm_load_si128(&in[i * 4 + 2]), _mm_load_si128(&in[i * 4 + 3])), + const __m128i words1 = _mm_srli_epi16( + _mm_packus_epi32(_mm_load_si128(&in[i * 4 + 2]), _mm_load_si128(&in[i * 4 + 3])), WeightScaleBits); - const __m128i packedbytes = _mm_packs_epi16(words0, words1); - _mm_store_si128(&out[i], _mm_max_epi8(packedbytes, Zero)); + _mm_store_si128(&out[i], _mm_packs_epi16(words0, words1)); } } constexpr IndexType Start = InputDimensions % SimdWidth == 0 @@ -109,9 +105,7 @@ class ClippedReLU { #elif defined(USE_SSE2) constexpr IndexType NumChunks = InputDimensions / SimdWidth; - #ifdef USE_SSE41 - const __m128i Zero = _mm_setzero_si128(); - #else + #ifndef USE_SSE41 const __m128i k0x80s = _mm_set1_epi8(-128); #endif @@ -119,6 +113,15 @@ class ClippedReLU { const auto out = reinterpret_cast<__m128i*>(output); for (IndexType i = 0; i < NumChunks; ++i) { + #if defined(USE_SSE41) + const __m128i words0 = _mm_srli_epi16( + _mm_packus_epi32(_mm_load_si128(&in[i * 4 + 0]), _mm_load_si128(&in[i * 4 + 1])), + WeightScaleBits); + const __m128i words1 = _mm_srli_epi16( + _mm_packus_epi32(_mm_load_si128(&in[i * 4 + 2]), _mm_load_si128(&in[i * 4 + 3])), + WeightScaleBits); + _mm_store_si128(&out[i], _mm_packs_epi16(words0, words1)); + #else const __m128i words0 = _mm_srai_epi16( _mm_packs_epi32(_mm_load_si128(&in[i * 4 + 0]), _mm_load_si128(&in[i * 4 + 1])), WeightScaleBits); @@ -126,15 +129,8 @@ class ClippedReLU { _mm_packs_epi32(_mm_load_si128(&in[i * 4 + 2]), _mm_load_si128(&in[i * 4 + 3])), WeightScaleBits); const __m128i packedbytes = _mm_packs_epi16(words0, words1); - _mm_store_si128(&out[i], - - #ifdef USE_SSE41 - _mm_max_epi8(packedbytes, Zero) - #else - _mm_subs_epi8(_mm_adds_epi8(packedbytes, k0x80s), k0x80s) + _mm_store_si128(&out[i], _mm_subs_epi8(_mm_adds_epi8(packedbytes, k0x80s), k0x80s)); #endif - - ); } constexpr IndexType Start = NumChunks * SimdWidth; diff --git a/src/nnue/nnue_misc.cpp b/src/nnue/nnue_misc.cpp index a13c717c3..b54bbaba3 100644 --- a/src/nnue/nnue_misc.cpp +++ b/src/nnue/nnue_misc.cpp @@ -178,14 +178,11 @@ trace(Position& pos, const Eval::NNUE::Networks& networks, Eval::NNUE::Accumulat ss << "| " << bucket << " "; ss << " | "; format_cp_aligned_dot(t.psqt[bucket], ss, pos); - ss << " " - << " | "; + ss << " " << " | "; format_cp_aligned_dot(t.positional[bucket], ss, pos); - ss << " " - << " | "; + ss << " " << " | "; format_cp_aligned_dot(t.psqt[bucket] + t.positional[bucket], ss, pos); - ss << " " - << " |"; + ss << " " << " |"; if (bucket == t.correctBucket) ss << " <-- this bucket is used"; ss << '\n'; diff --git a/src/tune.cpp b/src/tune.cpp index 3e5ebe5e6..84f59524f 100644 --- a/src/tune.cpp +++ b/src/tune.cpp @@ -59,8 +59,7 @@ void make_option(OptionsMap* options, const string& n, int v, const SetRange& r) // Print formatted parameters, ready to be copy-pasted in Fishtest std::cout << n << "," << v << "," << r(v).first << "," << r(v).second << "," - << (r(v).second - r(v).first) / 20.0 << "," - << "0.0020" << std::endl; + << (r(v).second - r(v).first) / 20.0 << "," << "0.0020" << std::endl; } } @@ -118,7 +117,6 @@ void Tune::Entry::read_option() { namespace Stockfish { -void Tune::read_results() { /* ...insert your values here... */ -} +void Tune::read_results() { /* ...insert your values here... */ } } // namespace Stockfish diff --git a/src/uci.cpp b/src/uci.cpp index cb686a027..cb9d7b085 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -286,9 +286,9 @@ void UCIEngine::bench(std::istream& args) { dbg_print(); - std::cerr << "\n===========================" - << "\nTotal time (ms) : " << elapsed << "\nNodes searched : " << nodes - << "\nNodes/second : " << 1000 * nodes / elapsed << std::endl; + std::cerr << "\n===========================" << "\nTotal time (ms) : " << elapsed + << "\nNodes searched : " << nodes << "\nNodes/second : " << 1000 * nodes / elapsed + << std::endl; // reset callback, to not capture a dangling reference to nodesSearched engine.set_on_update_full([&](const auto& i) { on_update_full(i, options["UCI_ShowWDL"]); }); From a3bb7e626d1489bbbcc16014b16065849ec786b5 Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Sun, 19 May 2024 10:12:05 +0200 Subject: [PATCH 34/44] Tweak continuation history bonus dependent on ply. This patch is based on following tuning https://tests.stockfishchess.org/tests/view/6648b2eb308cceea45533abe by only using the tuned factors for the continuation history. Passed STC: LLR: 2.94 (-2.94,2.94) <0.00,2.00> Total: 99904 W: 25865 L: 25457 D: 48582 Ptnml(0-2): 281, 11705, 25578, 12101, 287 https://tests.stockfishchess.org/tests/view/6648c136308cceea45533af8 Passed LTC: LLR: 2.96 (-2.94,2.94) <0.50,2.50> Total: 36402 W: 9362 L: 9039 D: 18001 Ptnml(0-2): 20, 3952, 9951, 4241, 37 https://tests.stockfishchess.org/tests/view/6648ee3cb8fa20e74c39f3fd closes https://github.com/official-stockfish/Stockfish/pull/5267 Bench: 1917762 --- src/search.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/search.cpp b/src/search.cpp index cbd454efb..5b9c9bb00 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1779,6 +1779,8 @@ void update_all_stats(const Position& pos, // by moves at ply -1, -2, -3, -4, and -6 with current move. void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus) { + bonus = bonus * (112 * ss->ply + 136) / (159 * ss->ply + 124); + for (int i : {1, 2, 3, 4, 6}) { // Only update the first 2 continuation histories if we are in check From 4a66a7c9caeca70ea8cd4527de7ec1e839b6cf46 Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Sun, 19 May 2024 18:48:43 +0300 Subject: [PATCH 35/44] Do more aggressive pawn history updates Tweak of recent patch that made pawn history to update for move that caused a fail low - and setting up default value of it to -900. This patch makes it more aggressive - twice bigger updates and default value -1100. Passed STC: https://tests.stockfishchess.org/tests/view/6648c5d4308cceea45533b5d LLR: 2.94 (-2.94,2.94) <0.00,2.00> Total: 235200 W: 61090 L: 60476 D: 113634 Ptnml(0-2): 763, 27952, 59651, 28376, 858 Passed LTC: https://tests.stockfishchess.org/tests/view/664a1008ae57c1758ac5b523 LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 20076 W: 5193 L: 4908 D: 9975 Ptnml(0-2): 7, 2105, 5534, 2380, 12 closes https://github.com/official-stockfish/Stockfish/pull/5268 Bench: 1590474 --- src/search.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 5b9c9bb00..2618b9847 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -496,7 +496,7 @@ void Search::Worker::clear() { counterMoves.fill(Move::none()); mainHistory.fill(0); captureHistory.fill(0); - pawnHistory.fill(-900); + pawnHistory.fill(-1100); correctionHistory.fill(0); for (bool inCheck : {false, true}) @@ -1339,7 +1339,7 @@ moves_loop: // When in check, search starts here if (type_of(pos.piece_on(prevSq)) != PAWN && ((ss - 1)->currentMove).type_of() != PROMOTION) thisThread->pawnHistory[pawn_structure_index(pos)][pos.piece_on(prevSq)][prevSq] - << stat_bonus(depth) * bonus * 2; + << stat_bonus(depth) * bonus * 4; } if (PvNode) From 81e21a69f02164fd988d5636a47c8790a1174b81 Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Sun, 19 May 2024 10:12:05 +0200 Subject: [PATCH 36/44] Simplify the recently introduced ply-based cmh bonus factor. Replace it with a constant which is an approximation of the limit of the factor. STC: LLR: 2.95 (-2.94,2.94) <-1.75,0.25> Total: 120064 W: 30967 L: 30836 D: 58261 Ptnml(0-2): 421, 14238, 30608, 14319, 446 https://tests.stockfishchess.org/tests/view/6649d146b8fa20e74c39f4ad LTC: LLR: 2.95 (-2.94,2.94) <-1.75,0.25> Total: 53856 W: 13719 L: 13530 D: 26607 Ptnml(0-2): 31, 5879, 14922, 6062, 34 https://tests.stockfishchess.org/tests/view/664a027fae57c1758ac5b4ee closes https://github.com/official-stockfish/Stockfish/pull/5270 Bench: 1355618 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 2618b9847..7e95dd878 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1779,7 +1779,7 @@ void update_all_stats(const Position& pos, // by moves at ply -1, -2, -3, -4, and -6 with current move. void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus) { - bonus = bonus * (112 * ss->ply + 136) / (159 * ss->ply + 124); + bonus = bonus * 45 / 64; for (int i : {1, 2, 3, 4, 6}) { From 4d88a63e607f44e59b9cc56b45984937e5eb123c Mon Sep 17 00:00:00 2001 From: Linmiao Xu Date: Sun, 19 May 2024 14:01:49 -0400 Subject: [PATCH 37/44] Re-eval only if smallnet output flips from simple eval Recent attempts to change the smallnet nnue re-eval threshold did not show much elo difference: https://tests.stockfishchess.org/tests/view/664a29bb25a9058c4d21d53c https://tests.stockfishchess.org/tests/view/664a299925a9058c4d21d53a Passed non-regression STC: https://tests.stockfishchess.org/tests/view/664a3ea95fc7b70b8817aee2 LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 22304 W: 5905 L: 5664 D: 10735 Ptnml(0-2): 67, 2602, 5603, 2783, 97 Passed non-regression LTC: https://tests.stockfishchess.org/tests/view/664a43d35fc7b70b8817aef4 LLR: 2.96 (-2.94,2.94) <-1.75,0.25> Total: 37536 W: 9667 L: 9460 D: 18409 Ptnml(0-2): 25, 4090, 10321, 4317, 15 closes https://github.com/official-stockfish/Stockfish/pull/5271 bench 1287409 --- src/evaluate.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index e5ebd45ae..2cf82eaf5 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -66,7 +66,7 @@ Value Eval::evaluate(const Eval::NNUE::Networks& networks, Value nnue = smallNet ? networks.small.evaluate(pos, &caches.small, true, &nnueComplexity) : networks.big.evaluate(pos, &caches.big, true, &nnueComplexity); - if (smallNet && (nnue * simpleEval < 0 || std::abs(nnue) < 500)) + if (smallNet && nnue * simpleEval < 0) { nnue = networks.big.evaluate(pos, &caches.big, true, &nnueComplexity); smallNet = false; From 0c797367a3a9783ff87422d543eb2106fea3e948 Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Mon, 20 May 2024 03:22:40 +0300 Subject: [PATCH 38/44] Update correction history in case of successful null move pruning Since null move pruning uses the same position it makes some sense to try to update correction history there in case of fail high. Update value is 4 times less than normal update. Passed STC: https://tests.stockfishchess.org/tests/view/664a011cae57c1758ac5b4dd LLR: 2.94 (-2.94,2.94) <0.00,2.00> Total: 419360 W: 108390 L: 107505 D: 203465 Ptnml(0-2): 1416, 49603, 106724, 50554, 1383 Passed LTC: https://tests.stockfishchess.org/tests/view/664a53d95fc7b70b8817c65b LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 193518 W: 49076 L: 48434 D: 96008 Ptnml(0-2): 89, 21335, 53263, 21989, 83 closes https://github.com/official-stockfish/Stockfish/pull/5272 bench 1301487 --- src/nnue/nnue_misc.cpp | 9 ++++++--- src/search.cpp | 9 +++++++++ 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/src/nnue/nnue_misc.cpp b/src/nnue/nnue_misc.cpp index b54bbaba3..a13c717c3 100644 --- a/src/nnue/nnue_misc.cpp +++ b/src/nnue/nnue_misc.cpp @@ -178,11 +178,14 @@ trace(Position& pos, const Eval::NNUE::Networks& networks, Eval::NNUE::Accumulat ss << "| " << bucket << " "; ss << " | "; format_cp_aligned_dot(t.psqt[bucket], ss, pos); - ss << " " << " | "; + ss << " " + << " | "; format_cp_aligned_dot(t.positional[bucket], ss, pos); - ss << " " << " | "; + ss << " " + << " | "; format_cp_aligned_dot(t.psqt[bucket] + t.positional[bucket], ss, pos); - ss << " " << " |"; + ss << " " + << " |"; if (bucket == t.correctBucket) ss << " <-- this bucket is used"; ss << '\n'; diff --git a/src/search.cpp b/src/search.cpp index 7e95dd878..2ed5d97bb 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -802,7 +802,16 @@ Value Search::Worker::search( if (nullValue >= beta && nullValue < VALUE_TB_WIN_IN_MAX_PLY) { if (thisThread->nmpMinPly || depth < 16) + { + if (nullValue >= ss->staticEval) + { + auto bonus = std::min(int(nullValue - ss->staticEval) * depth / 32, + CORRECTION_HISTORY_LIMIT / 16); + thisThread->correctionHistory[us][pawn_structure_index(pos)] + << bonus; + } return nullValue; + } assert(!thisThread->nmpMinPly); // Recursive verification is not allowed From b8ccaf038a21effba4613dca95f30eb1bc3d77b9 Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Mon, 20 May 2024 03:14:00 +0300 Subject: [PATCH 39/44] Use same shuffling Constant for both nets Passed STC: https://tests.stockfishchess.org/tests/view/664a42b15fc7b70b8817aeef LLR: 2.93 (-2.94,2.94) <-1.75,0.25> Total: 87840 W: 22759 L: 22594 D: 42487 Ptnml(0-2): 335, 10351, 22324, 10634, 276 Passed LTC: https://tests.stockfishchess.org/tests/view/664a46995fc7b70b8817af02 LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 163122 W: 41443 L: 41367 D: 80312 Ptnml(0-2): 105, 18154, 44927, 18310, 65 closes https://github.com/official-stockfish/Stockfish/pull/5273 bench: 1190174 --- src/evaluate.cpp | 2 +- src/tune.cpp | 6 ++++-- src/uci.cpp | 6 +++--- 3 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 2cf82eaf5..3a24657f9 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -80,7 +80,7 @@ Value Eval::evaluate(const Eval::NNUE::Networks& networks, v = (nnue * (npm + 943 + 11 * pos.count()) + optimism * (npm + 140)) / 1058; // Damp down the evaluation linearly when shuffling - v = v * ((smallNet ? 206 : 178) - pos.rule50_count()) / 207; + v = v * (204 - 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); diff --git a/src/tune.cpp b/src/tune.cpp index 84f59524f..3e5ebe5e6 100644 --- a/src/tune.cpp +++ b/src/tune.cpp @@ -59,7 +59,8 @@ void make_option(OptionsMap* options, const string& n, int v, const SetRange& r) // Print formatted parameters, ready to be copy-pasted in Fishtest std::cout << n << "," << v << "," << r(v).first << "," << r(v).second << "," - << (r(v).second - r(v).first) / 20.0 << "," << "0.0020" << std::endl; + << (r(v).second - r(v).first) / 20.0 << "," + << "0.0020" << std::endl; } } @@ -117,6 +118,7 @@ void Tune::Entry::read_option() { namespace Stockfish { -void Tune::read_results() { /* ...insert your values here... */ } +void Tune::read_results() { /* ...insert your values here... */ +} } // namespace Stockfish diff --git a/src/uci.cpp b/src/uci.cpp index cb9d7b085..cb686a027 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -286,9 +286,9 @@ void UCIEngine::bench(std::istream& args) { dbg_print(); - std::cerr << "\n===========================" << "\nTotal time (ms) : " << elapsed - << "\nNodes searched : " << nodes << "\nNodes/second : " << 1000 * nodes / elapsed - << std::endl; + std::cerr << "\n===========================" + << "\nTotal time (ms) : " << elapsed << "\nNodes searched : " << nodes + << "\nNodes/second : " << 1000 * nodes / elapsed << std::endl; // reset callback, to not capture a dangling reference to nodesSearched engine.set_on_update_full([&](const auto& i) { on_update_full(i, options["UCI_ShowWDL"]); }); From daf9787de197ce9e5478f3e7ceec8c64cb3d549a Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Tue, 21 May 2024 00:40:55 +0300 Subject: [PATCH 40/44] Rescale pawn history updates This patch is somewhat of a continuation of recent pawn history gainers. It makes pawn history updates after search twice smaller. Since on average they make pawn history more negative offset is changed to lower value to remain average value approximately the same. https://tests.stockfishchess.org/tests/view/664b3af9830eb9f886614aab Passed STC: LLR: 2.93 (-2.94,2.94) <0.00,2.00> Total: 170464 W: 44239 L: 43724 D: 82501 Ptnml(0-2): 523, 20278, 43128, 20767, 536 Passed LTC against pending PR : https://tests.stockfishchess.org/tests/view/664b8c58830eb9f886614b64 LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 98178 W: 25015 L: 24569 D: 48594 Ptnml(0-2): 48, 10769, 27005, 11223, 44 closes https://github.com/official-stockfish/Stockfish/pull/5275 Bench: 1343175 --- src/search.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 2ed5d97bb..4c5e521e7 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -496,7 +496,7 @@ void Search::Worker::clear() { counterMoves.fill(Move::none()); mainHistory.fill(0); captureHistory.fill(0); - pawnHistory.fill(-1100); + pawnHistory.fill(-1300); correctionHistory.fill(0); for (bool inCheck : {false, true}) @@ -1827,7 +1827,7 @@ void update_quiet_histories( update_continuation_histories(ss, pos.moved_piece(move), move.to_sq(), bonus); int pIndex = pawn_structure_index(pos); - workerThread.pawnHistory[pIndex][pos.moved_piece(move)][move.to_sq()] << bonus; + workerThread.pawnHistory[pIndex][pos.moved_piece(move)][move.to_sq()] << bonus / 2; } // Updates move sorting heuristics From f27a9be29c74b1d12babeb8a06ee992a22d67c9a Mon Sep 17 00:00:00 2001 From: Shawn Xu Date: Sat, 18 May 2024 03:19:36 -0700 Subject: [PATCH 41/44] Reduce When TTValue is Above Alpha Passed STC: LLR: 2.95 (-2.94,2.94) <0.00,2.00> Total: 53376 W: 13818 L: 13476 D: 26082 Ptnml(0-2): 156, 6212, 13626, 6522, 172 https://tests.stockfishchess.org/tests/view/664aa261830eb9f8866145e5 Passed LTC: LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 393444 W: 100096 L: 99042 D: 194306 Ptnml(0-2): 191, 43516, 108248, 44582, 185 https://tests.stockfishchess.org/tests/view/664ab54f830eb9f88661463c closes https://github.com/official-stockfish/Stockfish/pull/5276 Bench: 1024562 --- src/search.cpp | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 4c5e521e7..2817247d2 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -42,6 +42,7 @@ #include "thread.h" #include "timeman.h" #include "tt.h" +#include "types.h" #include "uci.h" #include "ucioption.h" @@ -833,9 +834,12 @@ Value Search::Worker::search( if (PvNode && !ttMove) depth -= 3; + if (!PvNode && ss->ttHit && (tte->bound() & BOUND_UPPER) && ttValue > alpha + 5 * depth) + depth--; + // Use qsearch if depth <= 0. if (depth <= 0) - return qsearch(pos, ss, alpha, beta); + return qsearch < PvNode ? PV : NonPV > (pos, ss, alpha, beta); // For cutNodes without a ttMove, we decrease depth by 2 if depth is high enough. if (cutNode && depth >= 8 && (!ttMove || tte->bound() == BOUND_UPPER)) From 87bad0c38a2b6a654850e61127dc0667a49acf82 Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Tue, 21 May 2024 02:19:54 +0300 Subject: [PATCH 42/44] Refine Evaluation Scaling with Piece-Specific Weights Refine Evaluation Scaling with Piece-Specific Weights, instead of the simplified npm method. I took the initial idea from Viren6 , as he worked on it in September of last year. I worked on it, and tuned it, and now it passed both tests. Passed STC: LLR: 2.94 (-2.94,2.94) <0.00,2.00> Total: 95712 W: 24731 L: 24325 D: 46656 Ptnml(0-2): 363, 11152, 24357, 11684, 300 https://tests.stockfishchess.org/tests/view/664b5493830eb9f886614af3 Passed LTC: LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 204480 W: 52167 L: 51501 D: 100812 Ptnml(0-2): 114, 22579, 56166, 23289, 92 https://tests.stockfishchess.org/tests/view/664b75dd830eb9f886614b44 closes https://github.com/official-stockfish/Stockfish/pull/5277 Bench: 1384337 --- src/evaluate.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 3a24657f9..44e69b3fd 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -76,8 +76,13 @@ Value Eval::evaluate(const Eval::NNUE::Networks& networks, optimism += optimism * (nnueComplexity + std::abs(simpleEval - nnue)) / 584; nnue -= nnue * (nnueComplexity * 5 / 3) / 32395; - int npm = pos.non_pawn_material() / 64; - v = (nnue * (npm + 943 + 11 * pos.count()) + optimism * (npm + 140)) / 1058; + v = (nnue + * (32961 + 381 * pos.count() + 349 * pos.count() + + 392 * pos.count() + 649 * pos.count() + 1211 * pos.count()) + + optimism + * (4835 + 136 * pos.count() + 375 * pos.count() + + 403 * pos.count() + 628 * pos.count() + 1124 * pos.count())) + / 32768; // Damp down the evaluation linearly when shuffling v = v * (204 - pos.rule50_count()) / 208; From c86ec8ec2916924065138770e0201c2cfe6d3e72 Mon Sep 17 00:00:00 2001 From: MinetaS Date: Tue, 21 May 2024 12:42:34 +0900 Subject: [PATCH 43/44] Remove cutoffCnt margin adjustment in razoring Passed non-regression STC: LLR: 2.95 (-2.94,2.94) <-1.75,0.25> Total: 65344 W: 16767 L: 16578 D: 31999 Ptnml(0-2): 198, 7557, 16987, 7718, 212 https://tests.stockfishchess.org/tests/view/664bd895830eb9f886615a26 Passed non-regression LTC: LLR: 2.96 (-2.94,2.94) <-1.75,0.25> Total: 35214 W: 8999 L: 8791 D: 17424 Ptnml(0-2): 16, 3804, 9760, 4010, 17 https://tests.stockfishchess.org/tests/view/664bead5830eb9f886615a52 closes https://github.com/official-stockfish/Stockfish/pull/5278 Bench: 1296223 --- src/search.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 2817247d2..a152b931e 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -762,8 +762,7 @@ Value Search::Worker::search( // Step 7. Razoring (~1 Elo) // If eval is really low check with qsearch if it can exceed alpha, if it can't, // return a fail low. - // Adjust razor margin according to cutoffCnt. (~1 Elo) - if (eval < alpha - 474 - (326 - 139 * ((ss + 1)->cutoffCnt > 3)) * depth * depth) + if (eval < alpha - 474 - 324 * depth * depth) { value = qsearch(pos, ss, alpha - 1, alpha); if (value < alpha) From c14b69790a62aad89fcc471cde482923dfe57f1e Mon Sep 17 00:00:00 2001 From: Linmiao Xu Date: Tue, 21 May 2024 13:55:20 -0400 Subject: [PATCH 44/44] Lower smallnet threshold with updated eval divisors Params found after 30k spsa games at 60+0.6, with initial values from 64k spsa games at 45+0.45 First spsa with 64k / 120k games at 45+0.45: https://tests.stockfishchess.org/tests/view/664a561b5fc7b70b8817c663 https://tests.stockfishchess.org/tests/view/664ae88e830eb9f8866146f9 Second spsa with 30k / 120k games at 60+0.6: https://tests.stockfishchess.org/tests/view/664be227830eb9f886615a36 Values found at 10k games at 60+0.6 also passed STC and LTC: https://tests.stockfishchess.org/tests/view/664bf4bd830eb9f886615a72 https://tests.stockfishchess.org/tests/view/664c0905830eb9f886615abf Passed STC: https://tests.stockfishchess.org/tests/view/664c139e830eb9f886615af2 LLR: 2.94 (-2.94,2.94) <0.00,2.00> Total: 69408 W: 18216 L: 17842 D: 33350 Ptnml(0-2): 257, 8275, 17401, 8379, 392 Passed LTC: https://tests.stockfishchess.org/tests/view/664cdaf7830eb9f886616a24 LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 35466 W: 9075 L: 8758 D: 17633 Ptnml(0-2): 27, 3783, 9794, 4104, 25 closes https://github.com/official-stockfish/Stockfish/pull/5280 bench 1301287 --- src/evaluate.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/evaluate.cpp b/src/evaluate.cpp index 44e69b3fd..ca09aaf9e 100644 --- a/src/evaluate.cpp +++ b/src/evaluate.cpp @@ -46,7 +46,7 @@ int Eval::simple_eval(const Position& pos, Color c) { bool Eval::use_smallnet(const Position& pos) { int simpleEval = simple_eval(pos, pos.side_to_move()); - return std::abs(simpleEval) > 1126 + 6 * pos.count(); + return std::abs(simpleEval) > 1018 + 5 * pos.count(); } // Evaluate is the evaluator for the outer world. It returns a static evaluation @@ -73,8 +73,8 @@ Value Eval::evaluate(const Eval::NNUE::Networks& networks, } // Blend optimism and eval with nnue complexity and material imbalance - optimism += optimism * (nnueComplexity + std::abs(simpleEval - nnue)) / 584; - nnue -= nnue * (nnueComplexity * 5 / 3) / 32395; + optimism += optimism * (nnueComplexity + std::abs(simpleEval - nnue)) / 620; + nnue -= nnue * (nnueComplexity * 5 / 3) / 32082; v = (nnue * (32961 + 381 * pos.count() + 349 * pos.count() @@ -82,7 +82,7 @@ Value Eval::evaluate(const Eval::NNUE::Networks& networks, + optimism * (4835 + 136 * pos.count() + 375 * pos.count() + 403 * pos.count() + 628 * pos.count() + 1124 * pos.count())) - / 32768; + / 36860; // Damp down the evaluation linearly when shuffling v = v * (204 - pos.rule50_count()) / 208;