From 793110ca194fd6e8c5933d175e9ad7b523a67d67 Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Fri, 11 Jul 2025 13:36:15 +0300 Subject: [PATCH 001/107] Remove !ttData.move condition from cutNode reduction Passed STC: LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 118080 W: 30427 L: 30298 D: 57355 Ptnml(0-2): 290, 13880, 30561, 14029, 280 https://tests.stockfishchess.org/tests/view/6853f9bc038630d25f468670 Passed LTC: LLR: 2.95 (-2.94,2.94) <-1.75,0.25> Total: 232272 W: 59187 L: 59182 D: 113903 Ptnml(0-2): 111, 25430, 65014, 25505, 76 https://tests.stockfishchess.org/tests/view/68585c40a596a06817bb922e closes https://github.com/official-stockfish/Stockfish/pull/6157 bench: 2227361 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index fae3fc39f..6c4d125b2 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1189,7 +1189,7 @@ moves_loop: // When in check, search starts here // Increase reduction for cut nodes if (cutNode) - r += 2864 + 966 * !ttData.move; + r += 3000; // Increase reduction if ttMove is a capture if (ttCapture) From 2c9a1871aeab32e882223d98001dc84a7cd481c2 Mon Sep 17 00:00:00 2001 From: Daniel Samek Date: Sun, 13 Jul 2025 11:01:34 +0200 Subject: [PATCH 002/107] Add offsets to history updates. All parameters were tuned on 60k STC games (https://tests.stockfishchess.org/tests/view/6867ef49fe0f2fe354c0c735). Passed STC: LLR: 2.98 (-2.94,2.94) <0.00,2.00> Total: 60576 W: 15794 L: 15444 D: 29338 Ptnml(0-2): 141, 7003, 15642, 7369, 133 https://tests.stockfishchess.org/tests/view/686d5af11451bd6fb830772a Passed LTC: LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 58722 W: 15159 L: 14799 D: 28764 Ptnml(0-2): 19, 6259, 16455, 6599, 29 https://tests.stockfishchess.org/tests/view/686f9fd51451bd6fb83081c9 closes https://github.com/official-stockfish/Stockfish/pull/6158 bench: 2706299 --- src/search.cpp | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 6c4d125b2..60ee42aba 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1872,13 +1872,16 @@ void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus) { static constexpr std::array conthist_bonuses = { {{1, 1092}, {2, 631}, {3, 294}, {4, 517}, {5, 126}, {6, 445}}}; + static constexpr int conthist_offsets[6]{71, 106, -22, -20, 29, -74}; + for (const auto [i, weight] : conthist_bonuses) { // Only update the first 2 continuation histories if we are in check if (ss->inCheck && i > 2) break; if (((ss - i)->currentMove).is_ok()) - (*(ss - i)->continuationHistory)[pc][to] << bonus * weight / 1024; + (*(ss - i)->continuationHistory)[pc][to] + << (bonus * weight / 1024) + conthist_offsets[i - 1]; } } @@ -1891,14 +1894,14 @@ void update_quiet_histories( workerThread.mainHistory[us][move.from_to()] << bonus; // Untuned to prevent duplicate effort if (ss->ply < LOW_PLY_HISTORY_SIZE) - workerThread.lowPlyHistory[ss->ply][move.from_to()] << bonus * 792 / 1024; + workerThread.lowPlyHistory[ss->ply][move.from_to()] << (bonus * 792 / 1024) + 40; update_continuation_histories(ss, pos.moved_piece(move), move.to_sq(), bonus * (bonus > 0 ? 1082 : 784) / 1024); int pIndex = pawn_structure_index(pos); workerThread.pawnHistory[pIndex][pos.moved_piece(move)][move.to_sq()] - << bonus * (bonus > 0 ? 705 : 450) / 1024; + << (bonus * (bonus > 0 ? 705 : 450) / 1024) + 70; } } From bdc393d3a2e95ba2c7a2c40f13ba21170d8befdc Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Sun, 13 Jul 2025 21:40:16 +0300 Subject: [PATCH 003/107] Correct comment closes https://github.com/official-stockfish/Stockfish/pull/6159 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 60ee42aba..65f1a79a5 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -891,7 +891,7 @@ Value Search::Worker::search( improving |= ss->staticEval >= beta + 94; // Step 10. Internal iterative reductions - // For PV nodes without a ttMove as well as for deep enough cutNodes, we decrease depth. + // At sufficient depth, reduce depth for PV/Cut nodes without a TTMove. // (*Scaler) Especially if they make IIR less aggressive. if (!allNode && depth >= 6 && !ttData.move) depth--; From e88ccfd835544ffa4ae44ebb1231d50b29143c19 Mon Sep 17 00:00:00 2001 From: Disservin Date: Tue, 15 Jul 2025 22:10:26 +0200 Subject: [PATCH 004/107] Prevent accidential misuse of TUNE() Writing a TUNE expression like int smallNetThreshold = 962; TUNE(smallNetThreshold, 850, 1050); is wrong and can lead to a weird binary. It should thus fail to even compile, with the proper intellisense you'll also see the error directly in your editor. A cheap way to prevent this is to disallow any fundamental type in the parameter list. closes https://github.com/official-stockfish/Stockfish/pull/6164 No functional change --- src/tune.h | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/tune.h b/src/tune.h index 4dab6bf45..d3c9ebaa3 100644 --- a/src/tune.h +++ b/src/tune.h @@ -170,11 +170,20 @@ class Tune { static OptionsMap* options; }; +template +constexpr void tune_check_args(Args&&...) { + static_assert((!std::is_fundamental_v && ...), "TUNE macro arguments wrong"); +} + // Some macro magic :-) we define a dummy int variable that the compiler initializes calling Tune::add() #define STRINGIFY(x) #x #define UNIQUE2(x, y) x##y #define UNIQUE(x, y) UNIQUE2(x, y) // Two indirection levels to expand __LINE__ -#define TUNE(...) int UNIQUE(p, __LINE__) = Tune::add(STRINGIFY((__VA_ARGS__)), __VA_ARGS__) +#define TUNE(...) \ + int UNIQUE(p, __LINE__) = []() -> int { \ + tune_check_args(__VA_ARGS__); \ + return Tune::add(STRINGIFY((__VA_ARGS__)), __VA_ARGS__); \ + }(); #define UPDATE_ON_LAST() bool UNIQUE(p, __LINE__) = Tune::update_on_last = true From 92514fd3a2bfe66e6d6fa8b89ec69b826bbc31c8 Mon Sep 17 00:00:00 2001 From: Daniel Monroe Date: Thu, 10 Jul 2025 23:06:36 -0400 Subject: [PATCH 005/107] Simplify away a term in see pruning This change only sets the margin to 0 when depth <= 2 and margin <= 42 which never has a difference, thus non-functional Passed non-regression STC LLR: 3.51 (-2.94,2.94) <-1.75,0.25> Total: 306976 W: 78935 L: 78961 D: 149080 Ptnml(0-2): 630, 34097, 84067, 34057, 637 https://tests.stockfishchess.org/tests/view/68708015fa93cf16d3bb2782 closes https://github.com/official-stockfish/Stockfish/pull/6170 No functional change --- src/search.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 65f1a79a5..e698e2c7f 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1047,8 +1047,8 @@ moves_loop: // When in check, search starts here } // SEE based pruning for captures and checks - int seeHist = std::clamp(captHist / 31, -137 * depth, 125 * depth); - if (!pos.see_ge(move, -158 * depth - seeHist)) + int margin = std::clamp(158 * depth + captHist / 31, 0, 283 * depth); + if (!pos.see_ge(move, -margin)) { bool mayStalemateTrap = depth > 2 && alpha < 0 && pos.non_pawn_material(us) == PieceValue[movedPiece] From a516b517d374bb9b4086dd2cc56be8f55d6aeba8 Mon Sep 17 00:00:00 2001 From: aronpetkovski Date: Tue, 15 Jul 2025 14:23:18 +0300 Subject: [PATCH 006/107] Simplify eval >= beta condition from NMP It seems that now only checking if static eval is above beta by some margin is all that's necessary. Passed Non-Regression STC LLR: 2.93 (-2.94,2.94) <-1.75,0.25> Total: 227264 W: 58430 L: 58421 D: 110413 Ptnml(0-2): 532, 26559, 59454, 26542, 545 https://tests.stockfishchess.org/tests/view/68763a77432ca24f6388c766 Passed Non-Regression LTC LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 72048 W: 18622 L: 18455 D: 34971 Ptnml(0-2): 26, 7775, 20272, 7908, 43 https://tests.stockfishchess.org/tests/view/687c9f2b6e17e7fa3939b0c5 closes https://github.com/official-stockfish/Stockfish/pull/6175 Bench: 2759840 --- AUTHORS | 1 + src/search.cpp | 4 +--- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/AUTHORS b/AUTHORS index b43a9e5b6..76b4f71ca 100644 --- a/AUTHORS +++ b/AUTHORS @@ -31,6 +31,7 @@ Andy Duplain Antoine Champion (antoinechampion) Aram Tumanian (atumanian) Arjun Temurnikar +Aron Petkovski (fury) Artem Solopiy (EntityFX) Auguste Pop Balazs Szilagyi diff --git a/src/search.cpp b/src/search.cpp index e698e2c7f..c5534924b 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -848,12 +848,10 @@ Value Search::Worker::search( } // Step 9. Null move search with verification search - if (cutNode && (ss - 1)->currentMove != Move::null() && eval >= beta + if (cutNode && (ss - 1)->currentMove != Move::null() && ss->staticEval >= beta - 19 * depth + 389 && !excludedMove && pos.non_pawn_material(us) && ss->ply >= nmpMinPly && !is_loss(beta)) { - assert(eval - beta >= 0); - // Null move dynamic reduction based on depth Depth R = 7 + depth / 3; From 90c83c381ff3858b688eebb548985d1d9dbe0875 Mon Sep 17 00:00:00 2001 From: Muzhen Gaming <61100393+XInTheDark@users.noreply.github.com> Date: Mon, 28 Jul 2025 00:04:02 +0800 Subject: [PATCH 007/107] VVLTC Search Tune alues were tuned with 125k VVLTC games. Passed VVLTC 1st sprt: https://tests.stockfishchess.org/tests/view/68865feb7b562f5f7b731341 LLR: 2.95 (-2.94,2.94) <0.00,2.00> Total: 39640 W: 10380 L: 10109 D: 19151 Ptnml(0-2): 5, 3556, 12424, 3833, 2 Passed VVLTC 2nd sprt: https://tests.stockfishchess.org/tests/view/68864dfa7b562f5f7b7312ee LLR: 2.95 (-2.94,2.94) <0.50,2.50> Total: 25972 W: 6807 L: 6537 D: 12628 Ptnml(0-2): 0, 2294, 8132, 2556, 4 closes https://github.com/official-stockfish/Stockfish/pull/6188 Bench: 3143696 --- src/search.cpp | 162 ++++++++++++++++++++++++------------------------- 1 file changed, 81 insertions(+), 81 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index c5534924b..41177b81c 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -83,7 +83,7 @@ int correction_value(const Worker& w, const Position& pos, const Stack* const ss m.is_ok() ? (*(ss - 2)->continuationCorrectionHistory)[pos.piece_on(m.to_sq())][m.to_sq()] : 0; - return 7696 * pcv + 7689 * micv + 9708 * (wnpcv + bnpcv) + 6978 * cntcv; + return 8867 * pcv + 8136 * micv + 10757 * (wnpcv + bnpcv) + 7232 * cntcv; } // Add correctionHistory value to raw staticEval and guarantee evaluation @@ -99,11 +99,11 @@ void update_correction_history(const Position& pos, const Move m = (ss - 1)->currentMove; const Color us = pos.side_to_move(); - static constexpr int nonPawnWeight = 172; + static constexpr int nonPawnWeight = 165; workerThread.pawnCorrectionHistory[pawn_structure_index(pos)][us] - << bonus * 111 / 128; - workerThread.minorPieceCorrectionHistory[minor_piece_index(pos)][us] << bonus * 151 / 128; + << bonus * 128 / 128; + workerThread.minorPieceCorrectionHistory[minor_piece_index(pos)][us] << bonus * 153 / 128; workerThread.nonPawnCorrectionHistory[non_pawn_index(pos)][WHITE][us] << bonus * nonPawnWeight / 128; workerThread.nonPawnCorrectionHistory[non_pawn_index(pos)][BLACK][us] @@ -111,7 +111,7 @@ void update_correction_history(const Position& pos, if (m.is_ok()) (*(ss - 2)->continuationCorrectionHistory)[pos.piece_on(m.to_sq())][m.to_sq()] - << bonus * 141 / 128; + << bonus * 153 / 128; } // Add a small random component to draw evaluations to avoid 3-fold blindness @@ -288,7 +288,7 @@ void Search::Worker::iterative_deepening() { int searchAgainCounter = 0; - lowPlyHistory.fill(86); + lowPlyHistory.fill(89); // Iterative deepening loop until requested to stop or the target depth is reached while (++rootDepth < MAX_PLY && !threads.stop @@ -324,13 +324,13 @@ void Search::Worker::iterative_deepening() { selDepth = 0; // Reset aspiration window starting size - delta = 5 + std::abs(rootMoves[pvIdx].meanSquaredScore) / 11134; + delta = 5 + std::abs(rootMoves[pvIdx].meanSquaredScore) / 11131; Value avg = rootMoves[pvIdx].averageScore; alpha = std::max(avg - delta, -VALUE_INFINITE); beta = std::min(avg + delta, VALUE_INFINITE); // Adjust optimism based on root move's averageScore - optimism[us] = 137 * avg / (std::abs(avg) + 91); + optimism[us] = 136 * avg / (std::abs(avg) + 93); optimism[~us] = -optimism[us]; // Start with a small aspiration window and, in the case of a fail @@ -538,9 +538,9 @@ void Search::Worker::undo_null_move(Position& pos) { pos.undo_null_move(); } // Reset histories, usually before a new game void Search::Worker::clear() { - mainHistory.fill(67); - captureHistory.fill(-688); - pawnHistory.fill(-1287); + mainHistory.fill(64); + captureHistory.fill(-753); + pawnHistory.fill(-1275); pawnCorrectionHistory.fill(5); minorPieceCorrectionHistory.fill(0); nonPawnCorrectionHistory.fill(0); @@ -555,10 +555,10 @@ void Search::Worker::clear() { for (StatsType c : {NoCaptures, Captures}) for (auto& to : continuationHistory[inCheck][c]) for (auto& h : to) - h.fill(-473); + h.fill(-494); for (size_t i = 1; i < reductions.size(); ++i) - reductions[i] = int(2796 / 128.0 * std::log(i)); + reductions[i] = int(2782 / 128.0 * std::log(i)); refreshTable.clear(networks[numaAccessToken]); } @@ -681,16 +681,16 @@ Value Search::Worker::search( // Bonus for a quiet ttMove that fails high if (!ttCapture) update_quiet_histories(pos, ss, *this, ttData.move, - std::min(125 * depth - 77, 1157)); + std::min(127 * depth - 74, 1063)); // Extra penalty for early quiet moves of the previous ply if (prevSq != SQ_NONE && (ss - 1)->moveCount <= 3 && !priorCapture) - update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq, -2301); + update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq, -2128); } // Partial workaround for the graph history interaction problem // For high rule50 counts don't produce transposition table cutoffs. - if (pos.rule50_count() < 90) + if (pos.rule50_count() < 91) { if (depth >= 8 && ttData.move && pos.pseudo_legal(ttData.move) && pos.legal(ttData.move) && !is_decisive(ttData.value)) @@ -803,11 +803,11 @@ Value Search::Worker::search( // Use static evaluation difference to improve quiet move ordering if (((ss - 1)->currentMove).is_ok() && !(ss - 1)->inCheck && !priorCapture && !ttHit) { - int bonus = std::clamp(-10 * int((ss - 1)->staticEval + ss->staticEval), -1858, 1492) + 661; - mainHistory[~us][((ss - 1)->currentMove).from_to()] << bonus * 1057 / 1024; + int bonus = std::clamp(-10 * int((ss - 1)->staticEval + ss->staticEval), -1979, 1561) + 630; + mainHistory[~us][((ss - 1)->currentMove).from_to()] << bonus * 935 / 1024; if (type_of(pos.piece_on(prevSq)) != PAWN && ((ss - 1)->currentMove).type_of() != PROMOTION) pawnHistory[pawn_structure_index(pos)][pos.piece_on(prevSq)][prevSq] - << bonus * 1266 / 1024; + << bonus * 1428 / 1024; } // Set up the improving flag, which is true if current static evaluation is @@ -820,26 +820,26 @@ Value Search::Worker::search( if (priorReduction >= 3 && !opponentWorsening) depth++; - if (priorReduction >= 1 && depth >= 2 && ss->staticEval + (ss - 1)->staticEval > 175) + if (priorReduction >= 2 && depth >= 2 && ss->staticEval + (ss - 1)->staticEval > 177) depth--; // Step 7. Razoring // If eval is really low, skip search entirely and return the qsearch value. // For PvNodes, we must have a guard against mates being returned. - if (!PvNode && eval < alpha - 486 - 325 * depth * depth) + if (!PvNode && eval < alpha - 495 - 290 * depth * depth) return qsearch(pos, ss, alpha, beta); // Step 8. Futility pruning: child node // The depth condition is important for mate finding. { auto futility_margin = [&](Depth d) { - Value futilityMult = 93 - 20 * (cutNode && !ss->ttHit); + Value futilityMult = 90 - 20 * (cutNode && !ss->ttHit); return futilityMult * d // - improving * futilityMult * 2 // - opponentWorsening * futilityMult / 3 // - + (ss - 1)->statScore / 376 // - + std::abs(correctionValue) / 168639; + + (ss - 1)->statScore / 356 // + + std::abs(correctionValue) / 171290; }; if (!ss->ttPv && depth < 14 && eval - futility_margin(depth) >= beta && eval >= beta @@ -849,7 +849,7 @@ Value Search::Worker::search( // Step 9. Null move search with verification search if (cutNode && (ss - 1)->currentMove != Move::null() - && ss->staticEval >= beta - 19 * depth + 389 && !excludedMove && pos.non_pawn_material(us) + && ss->staticEval >= beta - 19 * depth + 403 && !excludedMove && pos.non_pawn_material(us) && ss->ply >= nmpMinPly && !is_loss(beta)) { // Null move dynamic reduction based on depth @@ -886,7 +886,7 @@ Value Search::Worker::search( } } - improving |= ss->staticEval >= beta + 94; + improving |= ss->staticEval >= beta + 87; // Step 10. Internal iterative reductions // At sufficient depth, reduce depth for PV/Cut nodes without a TTMove. @@ -897,7 +897,7 @@ Value Search::Worker::search( // Step 11. ProbCut // 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 + 201 - 58 * improving; + probCutBeta = beta + 215 - 60 * improving; if (depth >= 3 && !is_decisive(beta) // If value from transposition table is lower than probCutBeta, don't attempt @@ -953,7 +953,7 @@ Value Search::Worker::search( moves_loop: // When in check, search starts here // Step 12. A small Probcut idea - probCutBeta = beta + 400; + probCutBeta = beta + 417; if ((ttData.bound & BOUND_LOWER) && ttData.depth >= depth - 4 && ttData.value >= probCutBeta && !is_decisive(beta) && is_valid(ttData.value) && !is_decisive(ttData.value)) return probCutBeta; @@ -1017,7 +1017,7 @@ moves_loop: // When in check, search starts here // Smaller or even negative value is better for short time controls // Bigger value is better for long time controls if (ss->ttPv) - r += 968; + r += 931; // Step 14. Pruning at shallow depth. // Depth conditions are important for mate finding. @@ -1038,7 +1038,7 @@ moves_loop: // When in check, search starts here // Futility pruning for captures if (!givesCheck && lmrDepth < 7 && !ss->inCheck) { - Value futilityValue = ss->staticEval + 232 + 224 * lmrDepth + Value futilityValue = ss->staticEval + 222 + 216 * lmrDepth + PieceValue[capturedPiece] + 131 * captHist / 1024; if (futilityValue <= alpha) continue; @@ -1067,21 +1067,21 @@ moves_loop: // When in check, search starts here + pawnHistory[pawn_structure_index(pos)][movedPiece][move.to_sq()]; // Continuation history based pruning - if (history < -4229 * depth) + if (history < -4361 * depth) continue; - history += 68 * mainHistory[us][move.from_to()] / 32; + history += 71 * mainHistory[us][move.from_to()] / 32; - lmrDepth += history / 3388; + lmrDepth += history / 3233; Value baseFutility = (bestMove ? 46 : 230); Value futilityValue = - ss->staticEval + baseFutility + 117 * lmrDepth + 102 * (ss->staticEval > alpha); + ss->staticEval + baseFutility + 131 * lmrDepth + 91 * (ss->staticEval > alpha); // Futility pruning: parent node // (*Scaler): Generally, more frequent futility pruning // scales well with respect to time and threads - if (!ss->inCheck && lmrDepth < 12 && futilityValue <= alpha) + if (!ss->inCheck && lmrDepth < 11 && futilityValue <= alpha) { if (bestValue <= futilityValue && !is_decisive(bestValue) && !is_win(futilityValue)) @@ -1092,7 +1092,7 @@ moves_loop: // When in check, search starts here lmrDepth = std::max(lmrDepth, 0); // Prune moves with negative SEE - if (!pos.see_ge(move, -27 * lmrDepth * lmrDepth)) + if (!pos.see_ge(move, -26 * lmrDepth * lmrDepth)) continue; } } @@ -1109,11 +1109,11 @@ moves_loop: // When in check, search starts here // and lower extension margins scale well. if (!rootNode && move == ttData.move && !excludedMove - && depth >= 6 - (completedDepth > 27) + ss->ttPv && is_valid(ttData.value) + && depth >= 6 - (completedDepth > 26) + ss->ttPv && is_valid(ttData.value) && !is_decisive(ttData.value) && (ttData.bound & BOUND_LOWER) && ttData.depth >= depth - 3) { - Value singularBeta = ttData.value - (58 + 76 * (ss->ttPv && !PvNode)) * depth / 57; + Value singularBeta = ttData.value - (56 + 79 * (ss->ttPv && !PvNode)) * depth / 58; Depth singularDepth = newDepth / 2; ss->excludedMove = move; @@ -1122,11 +1122,11 @@ moves_loop: // When in check, search starts here if (value < singularBeta) { - int corrValAdj = std::abs(correctionValue) / 248400; - int doubleMargin = -4 + 244 * PvNode - 206 * !ttCapture - corrValAdj - - 997 * ttMoveHistory / 131072 - (ss->ply > rootDepth) * 47; - int tripleMargin = 84 + 269 * PvNode - 253 * !ttCapture + 91 * ss->ttPv - corrValAdj - - (ss->ply * 2 > rootDepth * 3) * 54; + int corrValAdj = std::abs(correctionValue) / 249096; + int doubleMargin = 4 + 205 * PvNode - 223 * !ttCapture - corrValAdj + - 959 * ttMoveHistory / 131072 - (ss->ply > rootDepth) * 45; + int tripleMargin = 80 + 276 * PvNode - 249 * !ttCapture + 86 * ss->ttPv - corrValAdj + - (ss->ply * 2 > rootDepth * 3) * 53; extension = 1 + (value < singularBeta - doubleMargin) + (value < singularBeta - tripleMargin); @@ -1176,14 +1176,14 @@ moves_loop: // When in check, search starts here // Decrease reduction for PvNodes (*Scaler) if (ss->ttPv) - r -= 2437 + PvNode * 926 + (ttData.value > alpha) * 901 + r -= 2510 + PvNode * 963 + (ttData.value > alpha) * 916 + (ttData.depth >= depth) * (943 + cutNode * 1180); // These reduction adjustments have no proven non-linear scaling r += 650; // Base reduction offset to compensate for other tweaks - r -= moveCount * 66; - r -= std::abs(correctionValue) / 28047; + r -= moveCount * 69; + r -= std::abs(correctionValue) / 27160; // Increase reduction for cut nodes if (cutNode) @@ -1195,16 +1195,16 @@ moves_loop: // When in check, search starts here // Increase reduction if next ply has a lot of fail high if ((ss + 1)->cutoffCnt > 2) - r += 1036 + allNode * 848; + r += 935 + allNode * 763; - r += (ss + 1)->quietMoveStreak * 50; + r += (ss + 1)->quietMoveStreak * 51; // For first picked move (ttMove) reduce reduction if (move == ttData.move) - r -= 2006; + r -= 2043; if (capture) - ss->statScore = 826 * int(PieceValue[pos.captured_piece()]) / 128 + ss->statScore = 782 * int(PieceValue[pos.captured_piece()]) / 128 + captureHistory[movedPiece][move.to_sq()][type_of(pos.captured_piece())]; else ss->statScore = 2 * mainHistory[us][move.from_to()] @@ -1212,7 +1212,7 @@ moves_loop: // When in check, search starts here + (*contHist[1])[movedPiece][move.to_sq()]; // Decrease/increase reduction for moves with a good/bad history - r -= ss->statScore * 826 / 8192; + r -= ss->statScore * 789 / 8192; // Step 17. Late moves reduction / extension (LMR) if (depth >= 2 && moveCount > 1) @@ -1237,7 +1237,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 + 42 + 2 * newDepth); + const bool doDeeperSearch = value > (bestValue + 43 + 2 * newDepth); const bool doShallowerSearch = value < bestValue + 9; newDepth += doDeeperSearch - doShallowerSearch; @@ -1246,7 +1246,7 @@ moves_loop: // When in check, search starts here value = -search(pos, ss + 1, -(alpha + 1), -alpha, newDepth, !cutNode); // Post LMR continuation history updates - update_continuation_histories(ss, movedPiece, move.to_sq(), 1508); + update_continuation_histories(ss, movedPiece, move.to_sq(), 1412); } else if (value > alpha && value < bestValue + 9) newDepth--; @@ -1257,7 +1257,7 @@ moves_loop: // When in check, search starts here { // Increase reduction if ttMove is not present if (!ttData.move) - r += 1128; + r += 1139; // Note that if expected reduction is high, we reduce search depth here value = -search(pos, ss + 1, -(alpha + 1), -alpha, @@ -1343,7 +1343,7 @@ moves_loop: // When in check, search starts here // In case we have an alternative move equal in eval to the current bestmove, // promote it to bestmove by pretending it just exceeds alpha (but not beta). - int inc = (value == bestValue && ss->ply + 2 >= rootDepth && (int(nodes) & 15) == 0 + int inc = (value == bestValue && ss->ply + 2 >= rootDepth && (int(nodes) & 14) == 0 && !is_win(std::abs(value) + 1)); if (value + inc > bestValue) @@ -1406,31 +1406,31 @@ moves_loop: // When in check, search starts here update_all_stats(pos, ss, *this, bestMove, prevSq, quietsSearched, capturesSearched, depth, ttData.move, moveCount); if (!PvNode) - ttMoveHistory << (bestMove == ttData.move ? 800 : -879); + ttMoveHistory << (bestMove == ttData.move ? 811 : -848); } // Bonus for prior quiet countermove that caused the fail low else if (!priorCapture && prevSq != SQ_NONE) { - int bonusScale = -220; - bonusScale += std::min(-(ss - 1)->statScore / 103, 323); - bonusScale += std::min(73 * depth, 531); - bonusScale += 174 * ((ss - 1)->moveCount > 8); - bonusScale += 144 * (!ss->inCheck && bestValue <= ss->staticEval - 104); - bonusScale += 128 * (!(ss - 1)->inCheck && bestValue <= -(ss - 1)->staticEval - 82); + int bonusScale = -215; + bonusScale += std::min(-(ss - 1)->statScore / 103, 337); + bonusScale += std::min(64 * depth, 552); + bonusScale += 177 * ((ss - 1)->moveCount > 8); + bonusScale += 141 * (!ss->inCheck && bestValue <= ss->staticEval - 94); + bonusScale += 141 * (!(ss - 1)->inCheck && bestValue <= -(ss - 1)->staticEval - 76); bonusScale = std::max(bonusScale, 0); - const int scaledBonus = std::min(159 * depth - 94, 1501) * bonusScale; + const int scaledBonus = std::min(155 * depth - 88, 1416) * bonusScale; update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq, - scaledBonus * 412 / 32768); + scaledBonus * 397 / 32768); - mainHistory[~us][((ss - 1)->currentMove).from_to()] << scaledBonus * 203 / 32768; + mainHistory[~us][((ss - 1)->currentMove).from_to()] << scaledBonus * 224 / 32768; if (type_of(pos.piece_on(prevSq)) != PAWN && ((ss - 1)->currentMove).type_of() != PROMOTION) pawnHistory[pawn_structure_index(pos)][pos.piece_on(prevSq)][prevSq] - << scaledBonus * 1040 / 32768; + << scaledBonus * 1127 / 32768; } // Bonus for prior capture countermove that caused the fail low @@ -1438,7 +1438,7 @@ moves_loop: // When in check, search starts here { Piece capturedPiece = pos.captured_piece(); assert(capturedPiece != NO_PIECE); - captureHistory[pos.piece_on(prevSq)][prevSq][type_of(capturedPiece)] << 1080; + captureHistory[pos.piece_on(prevSq)][prevSq][type_of(capturedPiece)] << 1042; } if (PvNode) @@ -1588,7 +1588,7 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta) if (bestValue > alpha) alpha = bestValue; - futilityBase = ss->staticEval + 376; + futilityBase = ss->staticEval + 352; } const PieceToHistory* contHist[] = {(ss - 1)->continuationHistory, @@ -1649,7 +1649,7 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta) if (!capture && (*contHist[0])[pos.moved_piece(move)][move.to_sq()] + pawnHistory[pawn_structure_index(pos)][pos.moved_piece(move)][move.to_sq()] - <= 6218) + <= 5868) continue; // Do not search moves with bad enough SEE values @@ -1735,7 +1735,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) const { int reductionScale = reductions[d] * reductions[mn]; - return reductionScale - delta * 794 / rootDelta + !i * reductionScale * 205 / 512 + 1086; + return reductionScale - delta * 731 / rootDelta + !i * reductionScale * 216 / 512 + 1089; } // elapsed() returns the time elapsed since the search started. If the @@ -1831,35 +1831,35 @@ void update_all_stats(const Position& pos, Piece movedPiece = pos.moved_piece(bestMove); PieceType capturedPiece; - int bonus = std::min(143 * depth - 89, 1496) + 302 * (bestMove == ttMove); - int malus = std::min(737 * depth - 179, 3141) - 30 * moveCount; + int bonus = std::min(142 * depth - 88, 1501) + 318 * (bestMove == ttMove); + int malus = std::min(757 * depth - 172, 2848) - 30 * moveCount; if (!pos.capture_stage(bestMove)) { - update_quiet_histories(pos, ss, workerThread, bestMove, bonus * 1059 / 1024); + update_quiet_histories(pos, ss, workerThread, bestMove, bonus * 1054 / 1024); // Decrease stats for all non-best quiet moves for (Move move : quietsSearched) - update_quiet_histories(pos, ss, workerThread, move, -malus * 1310 / 1024); + update_quiet_histories(pos, ss, workerThread, move, -malus * 1388 / 1024); } else { // Increase stats for the best move in case it was a capture move capturedPiece = type_of(pos.piece_on(bestMove.to_sq())); - captureHistory[movedPiece][bestMove.to_sq()][capturedPiece] << bonus * 1213 / 1024; + captureHistory[movedPiece][bestMove.to_sq()][capturedPiece] << bonus * 1235 / 1024; } // Extra penalty for a quiet early move that was not a TT move in // previous ply when it gets refuted. if (prevSq != SQ_NONE && ((ss - 1)->moveCount == 1 + (ss - 1)->ttHit) && !pos.captured_piece()) - update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq, -malus * 580 / 1024); + update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq, -malus * 595 / 1024); // Decrease stats for all non-best capture moves for (Move move : capturesSearched) { movedPiece = pos.moved_piece(move); capturedPiece = type_of(pos.piece_on(move.to_sq())); - captureHistory[movedPiece][move.to_sq()][capturedPiece] << -malus * 1388 / 1024; + captureHistory[movedPiece][move.to_sq()][capturedPiece] << -malus * 1354 / 1024; } } @@ -1868,7 +1868,7 @@ void update_all_stats(const Position& pos, // at ply -1, -2, -3, -4, and -6 with current move. void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus) { static constexpr std::array conthist_bonuses = { - {{1, 1092}, {2, 631}, {3, 294}, {4, 517}, {5, 126}, {6, 445}}}; + {{1, 1108}, {2, 652}, {3, 273}, {4, 572}, {5, 126}, {6, 449}}}; static constexpr int conthist_offsets[6]{71, 106, -22, -20, 29, -74}; @@ -1892,14 +1892,14 @@ void update_quiet_histories( workerThread.mainHistory[us][move.from_to()] << bonus; // Untuned to prevent duplicate effort if (ss->ply < LOW_PLY_HISTORY_SIZE) - workerThread.lowPlyHistory[ss->ply][move.from_to()] << (bonus * 792 / 1024) + 40; + workerThread.lowPlyHistory[ss->ply][move.from_to()] << (bonus * 771 / 1024) + 40; update_continuation_histories(ss, pos.moved_piece(move), move.to_sq(), - bonus * (bonus > 0 ? 1082 : 784) / 1024); + bonus * (bonus > 0 ? 979 : 842) / 1024); int pIndex = pawn_structure_index(pos); workerThread.pawnHistory[pIndex][pos.moved_piece(move)][move.to_sq()] - << (bonus * (bonus > 0 ? 705 : 450) / 1024) + 70; + << (bonus * (bonus > 0 ? 704 : 439) / 1024) + 70; } } From b6082ba750b923401709bc7e32b21f807f4f541f Mon Sep 17 00:00:00 2001 From: Guenther Demetz Date: Fri, 25 Jul 2025 09:24:45 +0200 Subject: [PATCH 008/107] Simplify search functions according DRY principle Passed STC non-regression bounds https://tests.stockfishchess.org/tests/view/6870db4bfa93cf16d3bb286a LLR: 3.00 (-2.94,2.94) <-1.75,0.25> Total: 182016 W: 46735 L: 46673 D: 88608 Ptnml(0-2): 368, 19895, 50465, 19867, 413 closes https://github.com/official-stockfish/Stockfish/pull/6161 no functional change --- src/search.cpp | 43 ++++++++++++++----------------------------- src/search.h | 4 ++-- 2 files changed, 16 insertions(+), 31 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 41177b81c..cd84eb240 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -516,14 +516,21 @@ void Search::Worker::iterative_deepening() { } -void Search::Worker::do_move(Position& pos, const Move move, StateInfo& st) { - do_move(pos, move, st, pos.gives_check(move)); +void Search::Worker::do_move(Position& pos, const Move move, StateInfo& st, Stack* const ss) { + do_move(pos, move, st, pos.gives_check(move), ss); } -void Search::Worker::do_move(Position& pos, const Move move, StateInfo& st, const bool givesCheck) { +void Search::Worker::do_move(Position& pos, const Move move, StateInfo& st, const bool givesCheck, Stack* const ss) { + bool capture = pos.capture_stage(move); DirtyPiece dp = pos.do_move(move, st, givesCheck, &tt); nodes.fetch_add(1, std::memory_order_relaxed); accumulatorStack.push(dp); + if (ss != nullptr) + { + ss->currentMove = move; + ss->continuationHistory = &continuationHistory[ss->inCheck][capture][dp.pc][move.to_sq()]; + ss->continuationCorrectionHistory = &continuationCorrectionHistory[dp.pc][move.to_sq()]; + } } void Search::Worker::do_null_move(Position& pos, StateInfo& st) { pos.do_null_move(st, tt); } @@ -695,7 +702,7 @@ Value Search::Worker::search( if (depth >= 8 && ttData.move && pos.pseudo_legal(ttData.move) && pos.legal(ttData.move) && !is_decisive(ttData.value)) { - do_move(pos, ttData.move, st); + do_move(pos, ttData.move, st, nullptr); Key nextPosKey = pos.key(); auto [ttHitNext, ttDataNext, ttWriterNext] = tt.probe(nextPosKey); undo_move(pos, ttData.move); @@ -920,13 +927,7 @@ Value Search::Worker::search( movedPiece = pos.moved_piece(move); - do_move(pos, move, st); - - ss->currentMove = move; - ss->continuationHistory = - &continuationHistory[ss->inCheck][true][movedPiece][move.to_sq()]; - ss->continuationCorrectionHistory = - &continuationCorrectionHistory[movedPiece][move.to_sq()]; + do_move(pos, move, st, ss); // Perform a preliminary qsearch to verify that the move holds value = -qsearch(pos, ss + 1, -probCutBeta, -probCutBeta + 1); @@ -1161,17 +1162,10 @@ moves_loop: // When in check, search starts here } // Step 16. Make the move - do_move(pos, move, st, givesCheck); + do_move(pos, move, st, givesCheck, ss); // Add extension to new depth newDepth += extension; - - // Update the current move (this must be done after singular extension search) - ss->currentMove = move; - ss->continuationHistory = - &continuationHistory[ss->inCheck][capture][movedPiece][move.to_sq()]; - ss->continuationCorrectionHistory = - &continuationCorrectionHistory[movedPiece][move.to_sq()]; uint64_t nodeCount = rootNode ? uint64_t(nodes) : 0; // Decrease reduction for PvNodes (*Scaler) @@ -1658,16 +1652,7 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta) } // Step 7. Make and search the move - Piece movedPiece = pos.moved_piece(move); - - do_move(pos, move, st, givesCheck); - - // Update the current move - ss->currentMove = move; - ss->continuationHistory = - &continuationHistory[ss->inCheck][capture][movedPiece][move.to_sq()]; - ss->continuationCorrectionHistory = - &continuationCorrectionHistory[movedPiece][move.to_sq()]; + do_move(pos, move, st, givesCheck, ss); value = -qsearch(pos, ss + 1, -beta, -alpha); undo_move(pos, move); diff --git a/src/search.h b/src/search.h index e0b57e30b..a43649e94 100644 --- a/src/search.h +++ b/src/search.h @@ -297,8 +297,8 @@ class Worker { private: void iterative_deepening(); - void do_move(Position& pos, const Move move, StateInfo& st); - void do_move(Position& pos, const Move move, StateInfo& st, const bool givesCheck); + void do_move(Position& pos, const Move move, StateInfo& st, Stack* const ss); + void do_move(Position& pos, const Move move, StateInfo& st, const bool givesCheck, Stack* const ss); void do_null_move(Position& pos, StateInfo& st); void undo_move(Position& pos, const Move move); void undo_null_move(Position& pos); From 402602a70d29433cdc2eda1116d4e6cc68499b02 Mon Sep 17 00:00:00 2001 From: pb00067 Date: Sat, 26 Jul 2025 17:51:20 +0200 Subject: [PATCH 009/107] Simplify static evaluation difference to move ordering logic Passed STC simplification bounds https://tests.stockfishchess.org/tests/view/686fcb091451bd6fb83082bc LLR: 2.92 (-2.94,2.94) <-1.75,0.25> Total: 762816 W: 196717 L: 197295 D: 368804 Ptnml(0-2): 2052, 90457, 196853, 90109, 1937 Passed LTC simplification bounds https://tests.stockfishchess.org/tests/view/68808d316e17e7fa3939b35d LLR: 2.95 (-2.94,2.94) <-1.75,0.25> Total: 44736 W: 11499 L: 11303 D: 21934 Ptnml(0-2): 24, 4766, 12586, 4974, 18 closes https://github.com/official-stockfish/Stockfish/pull/6176 bench: 2684407 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index cd84eb240..27a4bea67 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -808,7 +808,7 @@ Value Search::Worker::search( } // Use static evaluation difference to improve quiet move ordering - if (((ss - 1)->currentMove).is_ok() && !(ss - 1)->inCheck && !priorCapture && !ttHit) + if (((ss - 1)->currentMove).is_ok() && !(ss - 1)->inCheck && !priorCapture) { int bonus = std::clamp(-10 * int((ss - 1)->staticEval + ss->staticEval), -1979, 1561) + 630; mainHistory[~us][((ss - 1)->currentMove).from_to()] << bonus * 935 / 1024; From 4fcfb0b4b7406004cd8adcf7de0b4acabe63c6c1 Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Sun, 27 Jul 2025 19:08:07 +0300 Subject: [PATCH 010/107] Tweak the logic for setting the improving flag Tweak the logic for setting the improving flag when the static evaluation is significantly higher than alpha. Passed STC: LLR: 2.93 (-2.94,2.94) <0.00,2.00> Total: 92320 W: 24057 L: 23664 D: 44599 Ptnml(0-2): 247, 10689, 23893, 11086, 245 https://tests.stockfishchess.org/tests/view/68860aba966ed85face248a1 Passed LTC: LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 281292 W: 72496 L: 71683 D: 137113 Ptnml(0-2): 135, 30289, 78995, 31082, 145 https://tests.stockfishchess.org/tests/view/6886168c966ed85face24962 closes https://github.com/official-stockfish/Stockfish/pull/6180 Bench: 3200439 --- src/search.cpp | 11 ++++++----- src/search.h | 3 ++- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 27a4bea67..9855d12e1 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -520,14 +520,15 @@ void Search::Worker::do_move(Position& pos, const Move move, StateInfo& st, Stac do_move(pos, move, st, pos.gives_check(move), ss); } -void Search::Worker::do_move(Position& pos, const Move move, StateInfo& st, const bool givesCheck, Stack* const ss) { - bool capture = pos.capture_stage(move); - DirtyPiece dp = pos.do_move(move, st, givesCheck, &tt); +void Search::Worker::do_move( + Position& pos, const Move move, StateInfo& st, const bool givesCheck, Stack* const ss) { + bool capture = pos.capture_stage(move); + DirtyPiece dp = pos.do_move(move, st, givesCheck, &tt); nodes.fetch_add(1, std::memory_order_relaxed); accumulatorStack.push(dp); if (ss != nullptr) { - ss->currentMove = move; + ss->currentMove = move; ss->continuationHistory = &continuationHistory[ss->inCheck][capture][dp.pc][move.to_sq()]; ss->continuationCorrectionHistory = &continuationCorrectionHistory[dp.pc][move.to_sq()]; } @@ -893,7 +894,7 @@ Value Search::Worker::search( } } - improving |= ss->staticEval >= beta + 87; + improving |= ss->staticEval >= beta + 94 * !PvNode; // Step 10. Internal iterative reductions // At sufficient depth, reduce depth for PV/Cut nodes without a TTMove. diff --git a/src/search.h b/src/search.h index a43649e94..07fc74317 100644 --- a/src/search.h +++ b/src/search.h @@ -298,7 +298,8 @@ class Worker { void iterative_deepening(); void do_move(Position& pos, const Move move, StateInfo& st, Stack* const ss); - void do_move(Position& pos, const Move move, StateInfo& st, const bool givesCheck, Stack* const ss); + void + do_move(Position& pos, const Move move, StateInfo& st, const bool givesCheck, Stack* const ss); void do_null_move(Position& pos, StateInfo& st); void undo_move(Position& pos, const Move move); void undo_null_move(Position& pos); From 9045fdb227fe5303822a2af290448f490401668b Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Sun, 27 Jul 2025 23:14:28 +0300 Subject: [PATCH 011/107] Add depth condition Passed STC: LLR: 2.94 (-2.94,2.94) <0.00,2.00> Total: 103360 W: 26941 L: 26530 D: 49889 Ptnml(0-2): 291, 11964, 26770, 12353, 302 https://tests.stockfishchess.org/tests/view/68863547966ed85face24a6f Passed LTC: LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 115128 W: 29734 L: 29258 D: 56136 Ptnml(0-2): 48, 12406, 32182, 12878, 50 https://tests.stockfishchess.org/tests/view/68864f867b562f5f7b7312f2 closes https://github.com/official-stockfish/Stockfish/pull/6184 Bench: 2972498 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 9855d12e1..24ba1c018 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -826,7 +826,7 @@ Value Search::Worker::search( opponentWorsening = ss->staticEval > -(ss - 1)->staticEval; - if (priorReduction >= 3 && !opponentWorsening) + if (priorReduction >= (depth < 10 ? 1 : 3) && !opponentWorsening) depth++; if (priorReduction >= 2 && depth >= 2 && ss->staticEval + (ss - 1)->staticEval > 177) depth--; From 2e2d2778fcae019f8cf53acedd5cb7b5a44696fb Mon Sep 17 00:00:00 2001 From: Nonlinear2 <131959792+Nonlinear2@users.noreply.github.com> Date: Mon, 28 Jul 2025 09:07:29 +0200 Subject: [PATCH 012/107] increase futility value when capturing last moved piece Passed STC: LLR: 2.95 (-2.94,2.94) <0.00,2.00> Total: 204320 W: 53059 L: 52500 D: 98761 Ptnml(0-2): 551, 23874, 52778, 24379, 578 https://tests.stockfishchess.org/tests/view/688618ae966ed85face24976 Passed LTC: LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 138582 W: 35748 L: 35225 D: 67609 Ptnml(0-2): 62, 14874, 38900, 15389, 66 https://tests.stockfishchess.org/tests/view/68862717966ed85face249f2 closes https://github.com/official-stockfish/Stockfish/pull/6190 Bench: 2894413 --- src/search.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 24ba1c018..c517fd496 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1040,8 +1040,9 @@ moves_loop: // When in check, search starts here // Futility pruning for captures if (!givesCheck && lmrDepth < 7 && !ss->inCheck) { - Value futilityValue = ss->staticEval + 222 + 216 * lmrDepth - + PieceValue[capturedPiece] + 131 * captHist / 1024; + Value futilityValue = ss->staticEval + 225 + 220 * lmrDepth + + 275 * (move.to_sq() == prevSq) + PieceValue[capturedPiece] + + 131 * captHist / 1024; if (futilityValue <= alpha) continue; } From a9b7638e966bf59b6216d319d57f65bc16395467 Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Sun, 27 Jul 2025 19:13:54 +0300 Subject: [PATCH 013/107] Simplify newDepth modification formulas Passed STC: LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 21856 W: 5709 L: 5471 D: 10676 Ptnml(0-2): 77, 2466, 5589, 2734, 62 https://tests.stockfishchess.org/tests/view/68862ea4966ed85face24a27 Passed LTC: LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 108828 W: 27893 L: 27763 D: 53172 Ptnml(0-2): 59, 11860, 30435, 12012, 48 https://tests.stockfishchess.org/tests/view/68863046966ed85face24a3b closes https://github.com/official-stockfish/Stockfish/pull/6181 Bench: 3069051 --- src/search.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index c517fd496..b0efea869 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1229,7 +1229,7 @@ moves_loop: // When in check, search starts here // Do a full-depth search when reduced LMR search fails high // (*Scaler) Usually doing more shallower searches // doesn't scale well to longer TCs - if (value > alpha && d < newDepth) + if (value > alpha) { // Adjust full-depth search based on LMR results - if the result was // good enough search deeper, if it was bad enough search shallower. @@ -1244,8 +1244,6 @@ moves_loop: // When in check, search starts here // Post LMR continuation history updates update_continuation_histories(ss, movedPiece, move.to_sq(), 1412); } - else if (value > alpha && value < bestValue + 9) - newDepth--; } // Step 18. Full-depth search when LMR is skipped From 1d8f118c3e8931676f5dbe967e227c7eedcc4449 Mon Sep 17 00:00:00 2001 From: 87 Date: Sun, 27 Jul 2025 20:15:24 +0100 Subject: [PATCH 014/107] Remove unnecessary deque allocation in perft closes https://github.com/official-stockfish/Stockfish/pull/6182 No functional change. --- src/perft.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/perft.h b/src/perft.h index 229debd40..e249a8e49 100644 --- a/src/perft.h +++ b/src/perft.h @@ -56,9 +56,9 @@ uint64_t perft(Position& pos, Depth depth) { } inline uint64_t perft(const std::string& fen, Depth depth, bool isChess960) { - StateListPtr states(new std::deque(1)); - Position p; - p.set(fen, isChess960, &states->back()); + StateInfo st; + Position p; + p.set(fen, isChess960, &st); return perft(p, depth); } From ab83d320b87f75de6ff01999193ec3f223b10fb2 Mon Sep 17 00:00:00 2001 From: Styx <164851643+styxdoto@users.noreply.github.com> Date: Sun, 27 Jul 2025 17:45:54 -0700 Subject: [PATCH 015/107] Simplify NMP condition As this is tried only for cutNode, and all children of cutNodes will be nonCutNodes, the guard condition is redundant. Simplification just removes the unnecessary condition (always true). closes https://github.com/official-stockfish/Stockfish/pull/6187 No functional change --- AUTHORS | 1 + src/search.cpp | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/AUTHORS b/AUTHORS index 76b4f71ca..273cab33b 100644 --- a/AUTHORS +++ b/AUTHORS @@ -231,6 +231,7 @@ Stefano Di Martino (StefanoD) Steinar Gunderson (sesse) Stéphane Nicolet (snicolet) Stephen Touset (stouset) +Styx (styxdoto) Syine Mineta (MinetaS) Taras Vuk (TarasVuk) Thanar2 diff --git a/src/search.cpp b/src/search.cpp index b0efea869..71a46ea7b 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -856,10 +856,11 @@ Value Search::Worker::search( } // Step 9. Null move search with verification search - if (cutNode && (ss - 1)->currentMove != Move::null() - && ss->staticEval >= beta - 19 * depth + 403 && !excludedMove && pos.non_pawn_material(us) - && ss->ply >= nmpMinPly && !is_loss(beta)) + if (cutNode && ss->staticEval >= beta - 19 * depth + 403 && !excludedMove + && pos.non_pawn_material(us) && ss->ply >= nmpMinPly && !is_loss(beta)) { + assert((ss - 1)->currentMove != Move::null()); + // Null move dynamic reduction based on depth Depth R = 7 + depth / 3; From 525a5749bc873a55893d8b4d4041b49ce074f407 Mon Sep 17 00:00:00 2001 From: Daniel Monroe Date: Sun, 27 Jul 2025 10:06:40 -0400 Subject: [PATCH 016/107] Simplify extra continuation history updates Passed simplification STC LLR: 2.95 (-2.94,2.94) <-1.75,0.25> Total: 254464 W: 65774 L: 65793 D: 122897 Ptnml(0-2): 699, 30087, 65638, 30150, 658 https://tests.stockfishchess.org/tests/view/68863283966ed85face24a59 Passed simplification LTC LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 144750 W: 37111 L: 37018 D: 70621 Ptnml(0-2): 79, 15676, 40764, 15785, 71 https://tests.stockfishchess.org/tests/view/6886655f7b562f5f7b731359 closes https://github.com/official-stockfish/Stockfish/pull/6189 Bench: 3071078 --- src/search.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 71a46ea7b..743f4bce7 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1856,16 +1856,13 @@ void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus) { static constexpr std::array conthist_bonuses = { {{1, 1108}, {2, 652}, {3, 273}, {4, 572}, {5, 126}, {6, 449}}}; - static constexpr int conthist_offsets[6]{71, 106, -22, -20, 29, -74}; - for (const auto [i, weight] : conthist_bonuses) { // Only update the first 2 continuation histories if we are in check if (ss->inCheck && i > 2) break; if (((ss - i)->currentMove).is_ok()) - (*(ss - i)->continuationHistory)[pc][to] - << (bonus * weight / 1024) + conthist_offsets[i - 1]; + (*(ss - i)->continuationHistory)[pc][to] << (bonus * weight / 1024) + 80 * (i < 2); } } From 64e8e1b247367018ebbce15f0d7cf5a56c7eaf56 Mon Sep 17 00:00:00 2001 From: aronpetkovski Date: Sun, 27 Jul 2025 13:07:47 +0200 Subject: [PATCH 017/107] Simplify LMR extension limit formula This patch simplifies the maximum depth formula that reductions in LMR can allow. Passed STC LLR: 2.93 (-2.94,2.94) <-1.75,0.25> Total: 35616 W: 9358 L: 9139 D: 17119 Ptnml(0-2): 101, 4051, 9278, 4284, 94 https://tests.stockfishchess.org/tests/view/688608cf966ed85face24882 Passed LTC LLR: 2.95 (-2.94,2.94) <-1.75,0.25> Total: 22284 W: 5833 L: 5613 D: 10838 Ptnml(0-2): 8, 2367, 6173, 2585, 9 https://tests.stockfishchess.org/tests/view/68860d7f966ed85face248d5 closes https://github.com/official-stockfish/Stockfish/pull/6191 Bench: 2902492 --- src/search.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 743f4bce7..6503cc14d 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1219,9 +1219,7 @@ moves_loop: // When in check, search starts here // beyond the first move depth. // To prevent problems when the max value is less than the min value, // std::clamp has been replaced by a more robust implementation. - Depth d = std::max(1, std::min(newDepth - r / 1024, - newDepth + !allNode + (PvNode && !bestMove))) - + PvNode; + Depth d = std::max(1, std::min(newDepth - r / 1024, newDepth + 1 + PvNode)) + PvNode; ss->reduction = newDepth - d; value = -search(pos, ss + 1, -(alpha + 1), -alpha, d, true); From 83071917e903581542670a87a036f5d02e13fb82 Mon Sep 17 00:00:00 2001 From: mstembera Date: Sun, 27 Jul 2025 16:09:01 -0700 Subject: [PATCH 018/107] Optimize find_nnz() using VBMI2 about a 0.7% speedup for the x86-64-avx512icl ARCH closes https://github.com/official-stockfish/Stockfish/pull/6186 No functional change --- .../layers/affine_transform_sparse_input.h | 31 ++++++++++++++++++- 1 file changed, 30 insertions(+), 1 deletion(-) diff --git a/src/nnue/layers/affine_transform_sparse_input.h b/src/nnue/layers/affine_transform_sparse_input.h index e77c98f8c..069210304 100644 --- a/src/nnue/layers/affine_transform_sparse_input.h +++ b/src/nnue/layers/affine_transform_sparse_input.h @@ -82,7 +82,36 @@ void find_nnz(const std::int32_t* RESTRICT input, std::uint16_t* RESTRICT out, IndexType& count_out) { - #ifdef USE_AVX512 + #if defined(USE_AVX512ICL) + + constexpr IndexType SimdWidthIn = 16; // 512 bits / 32 bits + constexpr IndexType SimdWidthOut = 32; // 512 bits / 16 bits + constexpr IndexType NumChunks = InputDimensions / SimdWidthOut; + const __m512i increment = _mm512_set1_epi16(SimdWidthOut); + __m512i base = _mm512_set_epi16(31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, + 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + + IndexType count = 0; + for (IndexType i = 0; i < NumChunks; ++i) + { + const __m512i inputV0 = _mm512_load_si512(input + i * 2 * SimdWidthIn); + const __m512i inputV1 = _mm512_load_si512(input + i * 2 * SimdWidthIn + SimdWidthIn); + + // Get a bitmask and gather non zero indices + const __mmask32 nnzMask = _mm512_kunpackw(_mm512_test_epi32_mask(inputV1, inputV1), + _mm512_test_epi32_mask(inputV0, inputV0)); + + // Avoid _mm512_mask_compressstoreu_epi16() as it's 256 uOps on Zen4 + __m512i nnz = _mm512_maskz_compress_epi16(nnzMask, base); + _mm512_storeu_epi16(out + count, nnz); + + count += popcount(nnzMask); + base = _mm512_add_epi16(base, increment); + } + count_out = count; + + #elif defined(USE_AVX512) + constexpr IndexType SimdWidth = 16; // 512 bits / 32 bits constexpr IndexType NumChunks = InputDimensions / SimdWidth; const __m512i increment = _mm512_set1_epi32(SimdWidth); From fdd9c34b75767aaebe8d348f3393735af07671a8 Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Tue, 29 Jul 2025 13:51:13 +0300 Subject: [PATCH 019/107] Re-adding ttHit condition, but this time in the inner block Passed STC: LLR: 2.94 (-2.94,2.94) <0.00,2.00> Total: 150240 W: 39305 L: 38819 D: 72116 Ptnml(0-2): 536, 17541, 38494, 17999, 550 https://tests.stockfishchess.org/tests/view/6887ce577b562f5f7b731a85 Passed LTC: LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 159120 W: 41025 L: 40461 D: 77634 Ptnml(0-2): 96, 16974, 44866, 17518, 106 https://tests.stockfishchess.org/tests/view/6887f0ba7b562f5f7b731c5d closes https://github.com/official-stockfish/Stockfish/pull/6193 bench: 3498926 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 6503cc14d..e3044bf6a 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -813,7 +813,7 @@ Value Search::Worker::search( { int bonus = std::clamp(-10 * int((ss - 1)->staticEval + ss->staticEval), -1979, 1561) + 630; mainHistory[~us][((ss - 1)->currentMove).from_to()] << bonus * 935 / 1024; - if (type_of(pos.piece_on(prevSq)) != PAWN && ((ss - 1)->currentMove).type_of() != PROMOTION) + if (!ttHit && type_of(pos.piece_on(prevSq)) != PAWN && ((ss - 1)->currentMove).type_of() != PROMOTION) pawnHistory[pawn_structure_index(pos)][pos.piece_on(prevSq)][prevSq] << bonus * 1428 / 1024; } From 32cb78d782b5918fb658622a2690ba871dc5bb06 Mon Sep 17 00:00:00 2001 From: MinetaS Date: Wed, 30 Jul 2025 15:55:35 +0900 Subject: [PATCH 020/107] Increase CI timeouts for perft might fix CI failures on macOS instances closes https://github.com/official-stockfish/Stockfish/pull/6194 No functional change --- tests/perft.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/perft.sh b/tests/perft.sh index 97c462c57..bb32bee56 100755 --- a/tests/perft.sh +++ b/tests/perft.sh @@ -16,7 +16,7 @@ EXPECT_SCRIPT=$(mktemp) cat << 'EOF' > $EXPECT_SCRIPT #!/usr/bin/expect -f -set timeout 30 +set timeout 120 lassign [lrange $argv 0 4] pos depth result chess960 logfile log_file -noappend $logfile spawn ./stockfish From 9034730a5a0f1f311dd21ef5afd5b3b9c86d9f83 Mon Sep 17 00:00:00 2001 From: "J. Oster" Date: Wed, 30 Jul 2025 11:21:06 +0200 Subject: [PATCH 021/107] Display upper/lowerbound before wdl Bound info belongs directly to score info closes https://github.com/official-stockfish/Stockfish/pull/6195 No functional change. --- src/uci.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/uci.cpp b/src/uci.cpp index 500e88184..9b1dd865c 100644 --- a/src/uci.cpp +++ b/src/uci.cpp @@ -630,12 +630,12 @@ void UCIEngine::on_update_full(const Engine::InfoFull& info, bool showWDL) { << " multipv " << info.multiPV // << " score " << format_score(info.score); // - if (showWDL) - ss << " wdl " << info.wdl; - if (!info.bound.empty()) ss << " " << info.bound; + if (showWDL) + ss << " wdl " << info.wdl; + ss << " nodes " << info.nodes // << " nps " << info.nps // << " hashfull " << info.hashfull // From cef551092c7d4ca4d9a2d6402f412332b1f3e88a Mon Sep 17 00:00:00 2001 From: aronpetkovski Date: Sun, 27 Jul 2025 22:39:12 +0200 Subject: [PATCH 022/107] Only do IIR in minimally reduced nodes Passed STC LLR: 2.93 (-2.94,2.94) <0.00,2.00> Total: 164256 W: 42799 L: 42299 D: 79158 Ptnml(0-2): 451, 19305, 42087, 19863, 422 https://tests.stockfishchess.org/tests/view/68868e9b7b562f5f7b731615 Passed LTC LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 279396 W: 71871 L: 71062 D: 136463 Ptnml(0-2): 126, 30117, 78404, 30924, 127 https://tests.stockfishchess.org/tests/view/6886a4977b562f5f7b731663 closes https://github.com/official-stockfish/Stockfish/pull/6196 Bench: 3490609 --- src/search.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index e3044bf6a..9775e46b1 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -813,7 +813,8 @@ Value Search::Worker::search( { int bonus = std::clamp(-10 * int((ss - 1)->staticEval + ss->staticEval), -1979, 1561) + 630; mainHistory[~us][((ss - 1)->currentMove).from_to()] << bonus * 935 / 1024; - if (!ttHit && type_of(pos.piece_on(prevSq)) != PAWN && ((ss - 1)->currentMove).type_of() != PROMOTION) + if (!ttHit && type_of(pos.piece_on(prevSq)) != PAWN + && ((ss - 1)->currentMove).type_of() != PROMOTION) pawnHistory[pawn_structure_index(pos)][pos.piece_on(prevSq)][prevSq] << bonus * 1428 / 1024; } @@ -900,7 +901,7 @@ Value Search::Worker::search( // Step 10. Internal iterative reductions // At sufficient depth, reduce depth for PV/Cut nodes without a TTMove. // (*Scaler) Especially if they make IIR less aggressive. - if (!allNode && depth >= 6 && !ttData.move) + if (!allNode && depth >= 6 && !ttData.move && priorReduction <= 3) depth--; // Step 11. ProbCut From 57b32f3e60e596fe1d2452a9548baa5b292fc724 Mon Sep 17 00:00:00 2001 From: CSTENTOR Date: Wed, 30 Jul 2025 15:35:57 +0200 Subject: [PATCH 023/107] Make Resetting the Aspiration Window after FailLow more aggressive MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Sets beta=(3alpha+beta)/4 when failLow. Before it was beta=(alpha+beta)/2, even though in theory we should be getting an upper bound from a failLow, we can’t trust the score that caused the failLow. Therefore beta=alpha doesn’t work. I made the buffer between the new beta to the bestValue that caused the failLow smaller. passed STC: https://tests.stockfishchess.org/tests/view/688674947b562f5f7b7315b5 LLR: 2.93 (-2.94,2.94) <0.00,2.00> Total: 119616 W: 31253 L: 30818 D: 57545 Ptnml(0-2): 313, 14028, 30724, 14397, 346 passed LTC: https://tests.stockfishchess.org/tests/view/6887e0ad7b562f5f7b731afc LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 96978 W: 24905 L: 24466 D: 47607 Ptnml(0-2): 59, 10376, 27183, 10809, 62 closes https://github.com/official-stockfish/Stockfish/pull/6197 bench: 3085519 --- AUTHORS | 1 + src/search.cpp | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index 273cab33b..15614effd 100644 --- a/AUTHORS +++ b/AUTHORS @@ -57,6 +57,7 @@ Ciekce clefrks Clemens L. (rn5f107s2) Cody Ho (aesrentai) +CSTENTOR Dale Weiler (graphitemaster) Daniel Axtens (daxtens) Daniel Dugovic (ddugovic) diff --git a/src/search.cpp b/src/search.cpp index 9775e46b1..268f9e2cc 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -371,7 +371,7 @@ void Search::Worker::iterative_deepening() { // otherwise exit the loop. if (bestValue <= alpha) { - beta = (alpha + beta) / 2; + beta = (3 * alpha + beta) / 4; alpha = std::max(bestValue - delta, -VALUE_INFINITE); failedHighCnt = 0; From cd52859bd5783337ae03ba0e73c472e55b3f1243 Mon Sep 17 00:00:00 2001 From: Daniel Monroe Date: Mon, 28 Jul 2025 19:11:04 -0400 Subject: [PATCH 024/107] Simplify improving term Set improving whenever ss->staticEval >= beta Passed simplification STC LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 38016 W: 10122 L: 9900 D: 17994 Ptnml(0-2): 143, 4388, 9747, 4564, 166 https://tests.stockfishchess.org/tests/view/688803917b562f5f7b7322eb Passed simplification LTC LLR: 2.95 (-2.94,2.94) <-1.75,0.25> Total: 21648 W: 5594 L: 5375 D: 10679 Ptnml(0-2): 12, 2241, 6096, 2466, 9 https://tests.stockfishchess.org/tests/view/688820397b562f5f7b73235d closes https://github.com/official-stockfish/Stockfish/pull/6198 Bench: 3576884 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 268f9e2cc..e151cc796 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -896,7 +896,7 @@ Value Search::Worker::search( } } - improving |= ss->staticEval >= beta + 94 * !PvNode; + improving |= ss->staticEval >= beta; // Step 10. Internal iterative reductions // At sufficient depth, reduce depth for PV/Cut nodes without a TTMove. From 62b958f5170bcf34e0cfa1abfa909b7de382c141 Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Fri, 1 Aug 2025 21:01:59 +0300 Subject: [PATCH 025/107] Remove code that is not used anywhere closes https://github.com/official-stockfish/Stockfish/pull/6201 No functional change --- src/bitboard.h | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/bitboard.h b/src/bitboard.h index f959bcb86..27ef89c0e 100644 --- a/src/bitboard.h +++ b/src/bitboard.h @@ -179,11 +179,6 @@ inline Bitboard between_bb(Square s1, Square s2) { return BetweenBB[s1][s2]; } -// Returns true if the squares s1, s2 and s3 are aligned either on a -// straight or on a diagonal line. -inline bool aligned(Square s1, Square s2, Square s3) { return line_bb(s1, s2) & s3; } - - // distance() functions return the distance between x and y, defined as the // number of steps for a king in x to reach y. From a37b38bdf0ad964363a7fef4b278ccc761a52c52 Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Sat, 2 Aug 2025 14:27:51 +0300 Subject: [PATCH 026/107] Add "d < newDepth" condition for doDeeperSearch Add "d < newDepth" condition for doDeeperSearch Passed STC: LLR: 2.97 (-2.94,2.94) <0.00,2.00> Total: 66144 W: 17512 L: 17148 D: 31484 Ptnml(0-2): 220, 7726, 16833, 8056, 237 https://tests.stockfishchess.org/tests/view/6887cce67b562f5f7b731a79 Passed LTC: LLR: 2.95 (-2.94,2.94) <0.50,2.50> Total: 411240 W: 106103 L: 105023 D: 200114 Ptnml(0-2): 256, 44249, 115566, 45257, 292 https://tests.stockfishchess.org/tests/view/6887ec527b562f5f7b731c37 closes https://github.com/official-stockfish/Stockfish/pull/6204 Bench: 2917036 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index e151cc796..baf6dfb62 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1233,7 +1233,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 + 43 + 2 * newDepth); + const bool doDeeperSearch = d < newDepth && value > (bestValue + 43 + 2 * newDepth); const bool doShallowerSearch = value < bestValue + 9; newDepth += doDeeperSearch - doShallowerSearch; From a6e34f128f185d9772e6b3ecc7fdbff448444718 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Sat, 2 Aug 2025 13:59:01 +0200 Subject: [PATCH 027/107] Fix icx profile-build fixes the issue pointed out in https://github.com/official-stockfish/Stockfish/pull/6202 closes https://github.com/official-stockfish/Stockfish/pull/6203 No functional change --- src/Makefile | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/Makefile b/src/Makefile index 40dceae0b..047a9e71c 100644 --- a/src/Makefile +++ b/src/Makefile @@ -590,6 +590,10 @@ endif # Locate the version in the same directory as the compiler used, # with fallback to a generic one if it can't be located LLVM_PROFDATA := $(dir $(realpath $(shell which $(CXX) 2> /dev/null)))llvm-profdata +# for icx +ifeq ($(wildcard $(LLVM_PROFDATA)),) + LLVM_PROFDATA := $(dir $(realpath $(shell which $(CXX) 2> /dev/null)))/compiler/llvm-profdata +endif ifeq ($(wildcard $(LLVM_PROFDATA)),) LLVM_PROFDATA := llvm-profdata endif @@ -1137,7 +1141,7 @@ icx-profile-make: all icx-profile-use: - $(XCRUN) llvm-profdata merge -output=stockfish.profdata *.profraw + $(XCRUN) $(LLVM_PROFDATA) merge -output=stockfish.profdata *.profraw $(MAKE) ARCH=$(ARCH) COMP=$(COMP) \ EXTRACXXFLAGS='-fprofile-instr-use=stockfish.profdata' \ EXTRALDFLAGS='-fprofile-use ' \ From 8e733d68fd8bcbb042af23d3c3f7375c44416b25 Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Sat, 2 Aug 2025 19:17:22 +0300 Subject: [PATCH 028/107] Refactor: Simplify pawn structure indexing Refactoring the mechanism for calculating pawn structure hash indices and make it consistent with the rest. closes https://github.com/official-stockfish/Stockfish/pull/6205 No functional change --- src/history.h | 12 +++++------- src/movepick.cpp | 2 +- src/search.cpp | 18 ++++++++---------- 3 files changed, 14 insertions(+), 18 deletions(-) diff --git a/src/history.h b/src/history.h index 46914789e..b2abd9cc0 100644 --- a/src/history.h +++ b/src/history.h @@ -44,14 +44,12 @@ static_assert((PAWN_HISTORY_SIZE & (PAWN_HISTORY_SIZE - 1)) == 0, static_assert((CORRECTION_HISTORY_SIZE & (CORRECTION_HISTORY_SIZE - 1)) == 0, "CORRECTION_HISTORY_SIZE has to be a power of 2"); -enum PawnHistoryType { - Normal, - Correction -}; +inline int pawn_history_index(const Position& pos) { + return pos.pawn_key() & (PAWN_HISTORY_SIZE - 1); +} -template -inline int pawn_structure_index(const Position& pos) { - return pos.pawn_key() & ((T == Normal ? PAWN_HISTORY_SIZE : CORRECTION_HISTORY_SIZE) - 1); +inline int pawn_correction_history_index(const Position& pos) { + return pos.pawn_key() & (CORRECTION_HISTORY_SIZE - 1); } inline int minor_piece_index(const Position& pos) { diff --git a/src/movepick.cpp b/src/movepick.cpp index 79b6f55a2..eb7c45837 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -158,7 +158,7 @@ ExtMove* MovePicker::score(MoveList& ml) { { // histories m.value = 2 * (*mainHistory)[us][m.from_to()]; - m.value += 2 * (*pawnHistory)[pawn_structure_index(pos)][pc][to]; + m.value += 2 * (*pawnHistory)[pawn_history_index(pos)][pc][to]; m.value += (*continuationHistory[0])[pc][to]; m.value += (*continuationHistory[1])[pc][to]; m.value += (*continuationHistory[2])[pc][to]; diff --git a/src/search.cpp b/src/search.cpp index baf6dfb62..3c17042ca 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -75,7 +75,7 @@ using SearchedList = ValueList; int correction_value(const Worker& w, const Position& pos, const Stack* const ss) { const Color us = pos.side_to_move(); const auto m = (ss - 1)->currentMove; - const auto pcv = w.pawnCorrectionHistory[pawn_structure_index(pos)][us]; + const auto pcv = w.pawnCorrectionHistory[pawn_correction_history_index(pos)][us]; const auto micv = w.minorPieceCorrectionHistory[minor_piece_index(pos)][us]; const auto wnpcv = w.nonPawnCorrectionHistory[non_pawn_index(pos)][WHITE][us]; const auto bnpcv = w.nonPawnCorrectionHistory[non_pawn_index(pos)][BLACK][us]; @@ -101,8 +101,7 @@ void update_correction_history(const Position& pos, static constexpr int nonPawnWeight = 165; - workerThread.pawnCorrectionHistory[pawn_structure_index(pos)][us] - << bonus * 128 / 128; + workerThread.pawnCorrectionHistory[pawn_correction_history_index(pos)][us] << bonus; workerThread.minorPieceCorrectionHistory[minor_piece_index(pos)][us] << bonus * 153 / 128; workerThread.nonPawnCorrectionHistory[non_pawn_index(pos)][WHITE][us] << bonus * nonPawnWeight / 128; @@ -815,7 +814,7 @@ Value Search::Worker::search( mainHistory[~us][((ss - 1)->currentMove).from_to()] << bonus * 935 / 1024; if (!ttHit && type_of(pos.piece_on(prevSq)) != PAWN && ((ss - 1)->currentMove).type_of() != PROMOTION) - pawnHistory[pawn_structure_index(pos)][pos.piece_on(prevSq)][prevSq] + pawnHistory[pawn_history_index(pos)][pos.piece_on(prevSq)][prevSq] << bonus * 1428 / 1024; } @@ -823,8 +822,7 @@ Value Search::Worker::search( // bigger than the previous static evaluation at our turn (if we were in // check at our previous move we go back until we weren't in check) and is // false otherwise. The improving flag is used in various pruning heuristics. - improving = ss->staticEval > (ss - 2)->staticEval; - + improving = ss->staticEval > (ss - 2)->staticEval; opponentWorsening = ss->staticEval > -(ss - 1)->staticEval; if (priorReduction >= (depth < 10 ? 1 : 3) && !opponentWorsening) @@ -1069,7 +1067,7 @@ moves_loop: // When in check, search starts here { int history = (*contHist[0])[movedPiece][move.to_sq()] + (*contHist[1])[movedPiece][move.to_sq()] - + pawnHistory[pawn_structure_index(pos)][movedPiece][move.to_sq()]; + + pawnHistory[pawn_history_index(pos)][movedPiece][move.to_sq()]; // Continuation history based pruning if (history < -4361 * depth) @@ -1423,7 +1421,7 @@ moves_loop: // When in check, search starts here mainHistory[~us][((ss - 1)->currentMove).from_to()] << scaledBonus * 224 / 32768; if (type_of(pos.piece_on(prevSq)) != PAWN && ((ss - 1)->currentMove).type_of() != PROMOTION) - pawnHistory[pawn_structure_index(pos)][pos.piece_on(prevSq)][prevSq] + pawnHistory[pawn_history_index(pos)][pos.piece_on(prevSq)][prevSq] << scaledBonus * 1127 / 32768; } @@ -1642,7 +1640,7 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta) // Continuation history based pruning if (!capture && (*contHist[0])[pos.moved_piece(move)][move.to_sq()] - + pawnHistory[pawn_structure_index(pos)][pos.moved_piece(move)][move.to_sq()] + + pawnHistory[pawn_history_index(pos)][pos.moved_piece(move)][move.to_sq()] <= 5868) continue; @@ -1879,7 +1877,7 @@ void update_quiet_histories( update_continuation_histories(ss, pos.moved_piece(move), move.to_sq(), bonus * (bonus > 0 ? 979 : 842) / 1024); - int pIndex = pawn_structure_index(pos); + int pIndex = pawn_history_index(pos); workerThread.pawnHistory[pIndex][pos.moved_piece(move)][move.to_sq()] << (bonus * (bonus > 0 ? 704 : 439) / 1024) + 70; } From 5d1505d8c7475fed854e51512113aa8238b7dafd Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Sun, 3 Aug 2025 00:33:14 +0300 Subject: [PATCH 029/107] Reintroduce reduction term in LMR for cutnodes This term increases reduction for cutnodes without tt move, term was simplified away recently. Passed STC: https://tests.stockfishchess.org/tests/view/688882007b562f5f7b73262f LLR: 2.95 (-2.94,2.94) <0.00,2.00> Total: 187616 W: 49367 L: 48824 D: 89425 Ptnml(0-2): 710, 21898, 48034, 22471, 695 Passed LTC: https://tests.stockfishchess.org/tests/view/688c71f4502b34dd5e71139a LLR: 2.95 (-2.94,2.94) <0.50,2.50> Total: 140280 W: 36280 L: 35750 D: 68250 Ptnml(0-2): 79, 15175, 39121, 15667, 98 closes https://github.com/official-stockfish/Stockfish/pull/6206 Bench: 2996732 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 3c17042ca..bf454bbe8 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1183,7 +1183,7 @@ moves_loop: // When in check, search starts here // Increase reduction for cut nodes if (cutNode) - r += 3000; + r += 3000 + 1024 * !ttData.move; // Increase reduction if ttMove is a capture if (ttCapture) From 14a2e50a3d3cb7eafdc5a33256496040d90cf1cd Mon Sep 17 00:00:00 2001 From: Shawn Xu Date: Wed, 30 Jul 2025 17:07:08 -0700 Subject: [PATCH 030/107] Simplify key after Passed Non-regression STC: LLR: 2.93 (-2.94,2.94) <-1.75,0.25> Total: 534016 W: 139438 L: 139771 D: 254807 Ptnml(0-2): 2098, 63469, 136136, 63278, 2027 https://tests.stockfishchess.org/tests/view/688ac64d502b34dd5e7110a4 Passed Non-regression LTC: LLR: 2.95 (-2.94,2.94) <-1.75,0.25> Total: 43980 W: 11346 L: 11149 D: 21485 Ptnml(0-2): 31, 4689, 12353, 4886, 31 https://tests.stockfishchess.org/tests/view/688ea8a47d68fe4f7f130eb3 closes https://github.com/official-stockfish/Stockfish/pull/6207 Bench: 2884232 --- src/search.cpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index bf454bbe8..32ad708c8 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -702,10 +702,10 @@ Value Search::Worker::search( if (depth >= 8 && ttData.move && pos.pseudo_legal(ttData.move) && pos.legal(ttData.move) && !is_decisive(ttData.value)) { - do_move(pos, ttData.move, st, nullptr); + pos.do_move(ttData.move, st); Key nextPosKey = pos.key(); auto [ttHitNext, ttDataNext, ttWriterNext] = tt.probe(nextPosKey); - undo_move(pos, ttData.move); + pos.undo_move(ttData.move); // Check that the ttValue after the tt move would also trigger a cutoff if (!is_valid(ttDataNext.value)) From 377a3a5269acc9a7961135e7f0c2232081047e38 Mon Sep 17 00:00:00 2001 From: Jost Triller Date: Wed, 30 Jul 2025 00:37:52 +0200 Subject: [PATCH 031/107] Depth dependent reduction threshold when full-depth re-search STC: https://tests.stockfishchess.org/tests/view/68894d577b562f5f7b73273b LLR: 2.98 (-2.94,2.94) <0.00,2.00> Total: 155072 W: 40651 L: 40150 D: 74271 Ptnml(0-2): 609, 18271, 39292, 18738, 626 LTC: https://tests.stockfishchess.org/tests/view/688c2705502b34dd5e71127a LLR: 2.95 (-2.94,2.94) <0.50,2.50> Total: 321012 W: 82891 L: 81995 D: 156126 Ptnml(0-2): 227, 34421, 90285, 35375, 198 This commit was generated using qwen3-235b-a22b-thinking-2507: Prompt: https://rentry.co/iqtaoht7 Reasoning/thinking: https://rentry.co/wm6t9hye closes https://github.com/official-stockfish/Stockfish/pull/6210 Bench: 2983938 --- AUTHORS | 1 + src/search.cpp | 6 +++++- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index 15614effd..6bf0745ad 100644 --- a/AUTHORS +++ b/AUTHORS @@ -125,6 +125,7 @@ Jonathan McDermid (jonathanmcdermid) Joost VandeVondele (vondele) Joseph Ellis (jhellis3) Joseph R. Prostko +Jost Triller (tsoj) Jörg Oster (joergoster) Julian Willemer (NightlyKing) jundery diff --git a/src/search.cpp b/src/search.cpp index 32ad708c8..b5e6e1be9 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1251,9 +1251,13 @@ moves_loop: // When in check, search starts here if (!ttData.move) r += 1139; + const int threshold1 = depth <= 4 ? 2000 : 3200; + const int threshold2 = depth <= 4 ? 3500 : 4600; + // Note that if expected reduction is high, we reduce search depth here value = -search(pos, ss + 1, -(alpha + 1), -alpha, - newDepth - (r > 3200) - (r > 4600 && newDepth > 2), !cutNode); + newDepth - (r > threshold1) - (r > threshold2 && newDepth > 2), + !cutNode); } // For PV nodes only, do a full PV search on the first move or after a fail high, From 94175524b1c06f1a4ce80a5640272a15120dcbbd Mon Sep 17 00:00:00 2001 From: rn5f107s2 Date: Thu, 31 Jul 2025 21:59:01 +0200 Subject: [PATCH 032/107] Only set ep square if ep capture is possible for positions such as: position fen rr6/2q2p1k/2P1b1pp/bB2P1n1/R2B2PN/p4P1P/P1Q4K/1R6 b - - 2 38 moves f7f5 position fen 8/p2r1pK1/6p1/1kp1P1P1/2p5/2P5/8/4R3 b - - 0 43 moves f7f5 position fen 4k3/4p3/2b3b1/3P1P2/4K3/8/8/8 b - - moves e7e5 ep is not possible for various reasons. Do not set the ep square and the do not change the zobrist key, as if ep were possible. This fixes 3-fold detection, which could in rare cases be observed as a warning generated by fastchess for PVs that continued beyond an actual 3-fold. Also fixes wrong evals for certain moves e.g. a2a1 for position fen 4k3/1b2p2b/8/3P1P2/4K3/8/8/r7 b - - 0 1 moves e7e5 e4e3 a1a2 e3e4 a2a1 e4f3 a1a2 f3e4 fixes https://github.com/official-stockfish/Stockfish/issues/6138 originally written and tested by rn5f107s2, with small buglet as https://tests.stockfishchess.org/tests/view/685af90843ce022d15794400 failed STC LLR: -2.93 (-2.94,2.94) <-1.75,0.25> Total: 130688 W: 33986 L: 34362 D: 62340 Ptnml(0-2): 414, 13292, 38302, 12928, 408 https://tests.stockfishchess.org/tests/view/688bcb35502b34dd5e7111c9 passed LTC LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 99018 W: 25402 L: 25273 D: 48343 Ptnml(0-2): 54, 9097, 31089, 9204, 65 https://tests.stockfishchess.org/tests/view/688c613c502b34dd5e7112d3 https://github.com/official-stockfish/Stockfish/pull/6211 Bench: 2946135 Co-authored-by: Joost VandeVondele --- src/Makefile | 2 +- src/position.cpp | 77 ++++++++++++++++++++++++++++++++++++++---------- 2 files changed, 63 insertions(+), 16 deletions(-) diff --git a/src/Makefile b/src/Makefile index 047a9e71c..cec623f52 100644 --- a/src/Makefile +++ b/src/Makefile @@ -903,7 +903,7 @@ help: echo "Supported archs:" && \ echo "" && \ echo "native > select the best architecture for the host processor (default)" && \ - echo "x86-64-avx512icl > x86 64-bit with minimum avx512 support of Intel Ice Lane or AMD Zen 4" && \ + echo "x86-64-avx512icl > x86 64-bit with minimum avx512 support of Intel Ice Lake or AMD Zen 4" && \ echo "x86-64-vnni512 > x86 64-bit with vnni 512bit support" && \ echo "x86-64-vnni256 > x86 64-bit with vnni 512bit support, limit operands to 256bit wide" && \ echo "x86-64-avx512 > x86 64-bit with avx512 support" && \ diff --git a/src/position.cpp b/src/position.cpp index 5e2c27822..4ac1369d4 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -717,6 +717,8 @@ DirtyPiece Position::do_move(Move m, Piece pc = piece_on(from); Piece captured = m.type_of() == EN_PASSANT ? make_piece(them, PAWN) : piece_on(to); + bool checkEP = false; + DirtyPiece dp; dp.pc = pc; dp.from = from; @@ -804,21 +806,14 @@ DirtyPiece Position::do_move(Move m, // Move the piece. The tricky Chess960 castling is handled earlier if (m.type_of() != CASTLING) - { - move_piece(from, to); - } // If the moving piece is a pawn do some special extra work if (type_of(pc) == PAWN) { - // Set en passant square if the moved pawn can be captured - if ((int(to) ^ int(from)) == 16 - && (attacks_bb(to - pawn_push(us), us) & pieces(them, PAWN))) - { - st->epSquare = to - pawn_push(us); - k ^= Zobrist::enpassant[file_of(st->epSquare)]; - } + // Check later if the en passant square needs to be set + if ((int(to) ^ int(from)) == 16) + checkEP = true; else if (m.type_of() == PROMOTION) { @@ -863,11 +858,6 @@ DirtyPiece Position::do_move(Move m, st->minorPieceKey ^= Zobrist::psq[pc][from] ^ Zobrist::psq[pc][to]; } - // Update the key with the final value - st->key = k; - if (tt) - prefetch(tt->first_entry(key())); - // Set capture piece st->capturedPiece = captured; @@ -879,6 +869,63 @@ DirtyPiece Position::do_move(Move m, // Update king attacks used for fast check detection set_check_info(); + // Accurate e.p. info is needed for correct zobrist key generation and 3-fold checking + while (checkEP) + { + auto updateEpSquare = [&] { + st->epSquare = to - pawn_push(us); + k ^= Zobrist::enpassant[file_of(st->epSquare)]; + }; + + Bitboard pawns = attacks_bb(to - pawn_push(us), us) & pieces(them, PAWN); + + // If there are no pawns attacking the ep square, ep is not possible + if (!pawns) + break; + + // If there are checkers other than the to be captured pawn, ep is never legal + if (checkers() & ~square_bb(to)) + break; + + if (more_than_one(pawns)) + { + // If there are two pawns potentially being abled to capture and at least one + // is not pinned, ep is legal as there are no horizontal exposed checks + if (!more_than_one(blockers_for_king(them) & pawns)) + { + updateEpSquare(); + break; + } + + // If there is no pawn on our king's file, and thus both pawns are pinned + // by bishops, ep is not legal as the king square must be in front of the to square. + // And because the ep square and the king are not on a common diagonal, either ep capture + // would expose the king to a check from one of the bishops + if (!(file_bb(square(them)) & pawns)) + break; + + // Otherwise remove the pawn on the king file, as an ep capture by it can never be legal and the + // check below relies on there only being one pawn + pawns &= ~file_bb(square(them)); + } + + Square ksq = square(them); + Square capsq = to; + Bitboard occupied = (pieces() ^ lsb(pawns) ^ capsq) | (to - pawn_push(us)); + + // If our king is not attacked after making the move, ep is legal. + if (!(attacks_bb(ksq, occupied) & pieces(us, QUEEN, ROOK)) + && !(attacks_bb(ksq, occupied) & pieces(us, QUEEN, BISHOP))) + updateEpSquare(); + + break; + } + + // Update the key with the final value + st->key = k; + if (tt) + prefetch(tt->first_entry(key())); + // Calculate the repetition info. It is the ply distance from the previous // occurrence of the same position, negative in the 3-fold case, or zero // if the position was not repeated. From b177b7394a5506b5a118eec96d5dd80ff3a10498 Mon Sep 17 00:00:00 2001 From: KazApps Date: Tue, 29 Jul 2025 13:12:44 +0900 Subject: [PATCH 033/107] Separate bonus/malus parameters for quiet and capture moves Parameters were tuned on 60k STC games. Passed STC LLR: 2.95 (-2.94,2.94) <0.00,2.00> Total: 16928 W: 4570 L: 4277 D: 8081 Ptnml(0-2): 57, 1905, 4270, 2152, 80 https://tests.stockfishchess.org/tests/view/688b4486502b34dd5e711122 Passed LTC LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 43602 W: 11373 L: 11041 D: 21188 Ptnml(0-2): 23, 4657, 12116, 4975, 30 https://tests.stockfishchess.org/tests/view/688c0eb5502b34dd5e71124b Passed non-regression VLTC LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 181016 W: 46335 L: 46281 D: 88400 Ptnml(0-2): 33, 18177, 54034, 18231, 33 https://tests.stockfishchess.org/tests/view/688e0a77f17748b4d23c822b closes https://github.com/official-stockfish/Stockfish/pull/6200 bench: 3435529 --- src/search.cpp | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index b5e6e1be9..39d9862be 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -129,8 +129,7 @@ void update_all_stats(const Position& pos, SearchedList& quietsSearched, SearchedList& capturesSearched, Depth depth, - Move TTMove, - int moveCount); + Move TTMove); } // namespace @@ -1400,7 +1399,7 @@ moves_loop: // When in check, search starts here else if (bestMove) { update_all_stats(pos, ss, *this, bestMove, prevSq, quietsSearched, capturesSearched, depth, - ttData.move, moveCount); + ttData.move); if (!PvNode) ttMoveHistory << (bestMove == ttData.move ? 811 : -848); } @@ -1811,42 +1810,44 @@ void update_all_stats(const Position& pos, SearchedList& quietsSearched, SearchedList& capturesSearched, Depth depth, - Move ttMove, - int moveCount) { + Move ttMove) { CapturePieceToHistory& captureHistory = workerThread.captureHistory; Piece movedPiece = pos.moved_piece(bestMove); PieceType capturedPiece; - int bonus = std::min(142 * depth - 88, 1501) + 318 * (bestMove == ttMove); - int malus = std::min(757 * depth - 172, 2848) - 30 * moveCount; + int quietBonus = std::min(170 * depth - 87, 1598) + 332 * (bestMove == ttMove); + int quietMalus = std::min(743 * depth - 180, 2287) - 33 * quietsSearched.size(); + int captureBonus = std::min(124 * depth - 62, 1245) + 336 * (bestMove == ttMove); + int captureMalus = std::min(708 * depth - 148, 2287) - 29 * capturesSearched.size(); if (!pos.capture_stage(bestMove)) { - update_quiet_histories(pos, ss, workerThread, bestMove, bonus * 1054 / 1024); + update_quiet_histories(pos, ss, workerThread, bestMove, quietBonus * 978 / 1024); // Decrease stats for all non-best quiet moves for (Move move : quietsSearched) - update_quiet_histories(pos, ss, workerThread, move, -malus * 1388 / 1024); + update_quiet_histories(pos, ss, workerThread, move, -quietMalus * 1115 / 1024); } else { // Increase stats for the best move in case it was a capture move capturedPiece = type_of(pos.piece_on(bestMove.to_sq())); - captureHistory[movedPiece][bestMove.to_sq()][capturedPiece] << bonus * 1235 / 1024; + captureHistory[movedPiece][bestMove.to_sq()][capturedPiece] << captureBonus * 1288 / 1024; } // Extra penalty for a quiet early move that was not a TT move in // previous ply when it gets refuted. if (prevSq != SQ_NONE && ((ss - 1)->moveCount == 1 + (ss - 1)->ttHit) && !pos.captured_piece()) - update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq, -malus * 595 / 1024); + update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq, + -captureMalus * 622 / 1024); // Decrease stats for all non-best capture moves for (Move move : capturesSearched) { movedPiece = pos.moved_piece(move); capturedPiece = type_of(pos.piece_on(move.to_sq())); - captureHistory[movedPiece][move.to_sq()][capturedPiece] << -malus * 1354 / 1024; + captureHistory[movedPiece][move.to_sq()][capturedPiece] << -captureMalus * 1431 / 1024; } } From 303fe9a1643b40a667923cba122e36beffde288c Mon Sep 17 00:00:00 2001 From: Stockfisher69 Date: Sat, 2 Aug 2025 23:01:50 +0200 Subject: [PATCH 034/107] Simplification: Futility pruning for captures tested in final form as simplication passed LTC: LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 113682 W: 29199 L: 29074 D: 55409 Ptnml(0-2): 68, 12359, 31859, 12490, 65 https://tests.stockfishchess.org/tests/view/688e85a17d68fe4f7f130e24 earlier test, equivalent: passed STC: LLR: 2.96 (-2.94,2.94) <0.00,2.00> Total: 120224 W: 31621 L: 31176 D: 57427 Ptnml(0-2): 415, 14167, 30567, 14484, 479 https://tests.stockfishchess.org/tests/view/68888bdd7b562f5f7b732643 closes https://github.com/official-stockfish/Stockfish/pull/6209 Bench: 2661621 --- AUTHORS | 1 + src/search.cpp | 7 ++++--- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/AUTHORS b/AUTHORS index 6bf0745ad..e606e5a8d 100644 --- a/AUTHORS +++ b/AUTHORS @@ -233,6 +233,7 @@ Stefano Di Martino (StefanoD) Steinar Gunderson (sesse) Stéphane Nicolet (snicolet) Stephen Touset (stouset) +Stockfisher69 Styx (styxdoto) Syine Mineta (MinetaS) Taras Vuk (TarasVuk) diff --git a/src/search.cpp b/src/search.cpp index 39d9862be..b807ae7d1 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1039,9 +1039,10 @@ moves_loop: // When in check, search starts here // Futility pruning for captures if (!givesCheck && lmrDepth < 7 && !ss->inCheck) { - Value futilityValue = ss->staticEval + 225 + 220 * lmrDepth - + 275 * (move.to_sq() == prevSq) + PieceValue[capturedPiece] - + 131 * captHist / 1024; + + Value futilityValue = ss->staticEval + 232 + 224 * lmrDepth + + PieceValue[capturedPiece] + 131 * captHist / 1024; + if (futilityValue <= alpha) continue; } From 125a0cfe7b37064f6200ed526b96b5361a974317 Mon Sep 17 00:00:00 2001 From: Niklas Fiekas Date: Thu, 7 Aug 2025 22:57:01 +0200 Subject: [PATCH 035/107] Build x86-64-avx512icl in CI closes https://github.com/official-stockfish/Stockfish/pull/6217 No functional change --- .github/ci/matrix.json | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/.github/ci/matrix.json b/.github/ci/matrix.json index c414c51fc..57c97686c 100644 --- a/.github/ci/matrix.json +++ b/.github/ci/matrix.json @@ -63,6 +63,7 @@ "x86-64-avx512", "x86-64-vnni256", "x86-64-vnni512", + "x86-64-avx512icl", "apple-silicon", "armv8", "armv8-dotprod" @@ -116,6 +117,12 @@ "os": "macos-14" } }, + { + "binaries": "x86-64-avx512icl", + "config": { + "os": "macos-14" + } + }, { "binaries": "x86-64-avxvnni", "config": { @@ -140,6 +147,12 @@ "os": "macos-13" } }, + { + "binaries": "x86-64-avx512icl", + "config": { + "os": "macos-13" + } + }, { "binaries": "x86-64", "config": { @@ -188,6 +201,12 @@ "os": "windows-11-arm" } }, + { + "binaries": "x86-64-avx512icl", + "config": { + "os": "windows-11-arm" + } + }, { "binaries": "apple-silicon", "config": { From 5464f7b114c77fe5ccd7e3058fe5a92c3e7fc08a Mon Sep 17 00:00:00 2001 From: mstembera Date: Sun, 3 Aug 2025 19:10:31 -0700 Subject: [PATCH 036/107] Remove an instruction from find_nnz() closes https://github.com/official-stockfish/Stockfish/pull/6212 No functional change --- src/nnue/layers/affine_transform_sparse_input.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/nnue/layers/affine_transform_sparse_input.h b/src/nnue/layers/affine_transform_sparse_input.h index 069210304..685cf8ea1 100644 --- a/src/nnue/layers/affine_transform_sparse_input.h +++ b/src/nnue/layers/affine_transform_sparse_input.h @@ -88,8 +88,9 @@ void find_nnz(const std::int32_t* RESTRICT input, constexpr IndexType SimdWidthOut = 32; // 512 bits / 16 bits constexpr IndexType NumChunks = InputDimensions / SimdWidthOut; const __m512i increment = _mm512_set1_epi16(SimdWidthOut); - __m512i base = _mm512_set_epi16(31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, 16, - 15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + __m512i base = _mm512_set_epi16( // Same permute order as _mm512_packus_epi32() + 31, 30, 29, 28, 15, 14, 13, 12, 27, 26, 25, 24, 11, 10, 9, 8, 23, 22, 21, 20, 7, 6, 5, 4, 19, + 18, 17, 16, 3, 2, 1, 0); IndexType count = 0; for (IndexType i = 0; i < NumChunks; ++i) @@ -98,8 +99,8 @@ void find_nnz(const std::int32_t* RESTRICT input, const __m512i inputV1 = _mm512_load_si512(input + i * 2 * SimdWidthIn + SimdWidthIn); // Get a bitmask and gather non zero indices - const __mmask32 nnzMask = _mm512_kunpackw(_mm512_test_epi32_mask(inputV1, inputV1), - _mm512_test_epi32_mask(inputV0, inputV0)); + const __m512i inputV01 = _mm512_packus_epi32(inputV0, inputV1); + const __mmask32 nnzMask = _mm512_test_epi16_mask(inputV01, inputV01); // Avoid _mm512_mask_compressstoreu_epi16() as it's 256 uOps on Zen4 __m512i nnz = _mm512_maskz_compress_epi16(nnzMask, base); From ade891744714c40a339764693258dc82040e39f0 Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Thu, 7 Aug 2025 00:10:36 +0300 Subject: [PATCH 037/107] Remove outdated comment Remove the Elo worth, as they are now completely outdated, making them irrelevant and potentially misleading Continuation of #5810 as these comments in "history.h" were missed. closes https://github.com/official-stockfish/Stockfish/pull/6216 No functional change --- src/history.h | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/history.h b/src/history.h index b2abd9cc0..faf4af3d7 100644 --- a/src/history.h +++ b/src/history.h @@ -101,7 +101,7 @@ using Stats = MultiArray, Sizes...>; // ButterflyHistory records how often quiet moves have been successful or unsuccessful // during the current search, and is used for reduction and move ordering decisions. // It uses 2 tables (one for each color) indexed by the move's from and to squares, -// see https://www.chessprogramming.org/Butterfly_Boards (~11 elo) +// see https://www.chessprogramming.org/Butterfly_Boards using ButterflyHistory = Stats; // LowPlyHistory is adressed by play and move's from and to squares, used @@ -118,7 +118,6 @@ using PieceToHistory = Stats; // ContinuationHistory is the combined history of a given pair of moves, usually // the current one given a previous one. The nested history table is based on // PieceToHistory instead of ButterflyBoards. -// (~63 elo) using ContinuationHistory = MultiArray; // PawnHistory is addressed by the pawn structure and a move's [piece][to] From 7a07ac0e768a2d0c6b3c6b31470a3d822d94c15c Mon Sep 17 00:00:00 2001 From: Jost Triller Date: Tue, 5 Aug 2025 22:38:32 +0200 Subject: [PATCH 038/107] Adjust probcut on staticEval Reducing probcut depth more when staticEval is very good and less if staticEval is not so good compared to beta STC: https://tests.stockfishchess.org/tests/view/68926bf6690844f940fa1350 LLR: 2.98 (-2.94,2.94) <0.00,2.00> Total: 174400 W: 45698 L: 45174 D: 83528 Ptnml(0-2): 622, 20356, 44672, 20976, 574 LTC: https://tests.stockfishchess.org/tests/view/689651b4f8a258623dda6531 LLR: 2.95 (-2.94,2.94) <0.50,2.50> Total: 56010 W: 14547 L: 14191 D: 27272 Ptnml(0-2): 31, 5929, 15738, 6267, 40 This patch was generated using qwen3-235b-a22b-thinking-2507: Prompt: https://rentry.co/bm6vriai Thinking: https://rentry.co/34km4zf8 Final respone: https://rentry.co/rauotrvr closes https://github.com/official-stockfish/Stockfish/pull/6219 Bench: 3629755 --- src/search.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index b807ae7d1..3bf460a1a 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -914,7 +914,8 @@ Value Search::Worker::search( assert(probCutBeta < VALUE_INFINITE && probCutBeta > beta); MovePicker mp(pos, ttData.move, probCutBeta - ss->staticEval, &captureHistory); - Depth probCutDepth = std::max(depth - 5, 0); + Depth dynamicReduction = (ss->staticEval - beta) / 300; + Depth probCutDepth = std::max(depth - 5 - dynamicReduction, 0); while ((move = mp.next_move()) != Move::none()) { From 0383670cd556496ab3b3059f9a1fe10f44eef274 Mon Sep 17 00:00:00 2001 From: mstembera Date: Fri, 15 Aug 2025 14:41:55 -0700 Subject: [PATCH 039/107] Avoid using _mm512_storeu_epi16() gcc 9 & 10 do not provide this function, instead use the generic _mm512_storeu_si512 https://gcc.gnu.org/bugzilla/show_bug.cgi?id=95483 https://tests.stockfishchess.org/actions?max_actions=1&action=&user=&text=&before=1755266300.455175&run_id= closes https://github.com/official-stockfish/Stockfish/pull/6231 No functional change --- src/nnue/layers/affine_transform_sparse_input.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/nnue/layers/affine_transform_sparse_input.h b/src/nnue/layers/affine_transform_sparse_input.h index 685cf8ea1..a073c6196 100644 --- a/src/nnue/layers/affine_transform_sparse_input.h +++ b/src/nnue/layers/affine_transform_sparse_input.h @@ -104,7 +104,7 @@ void find_nnz(const std::int32_t* RESTRICT input, // Avoid _mm512_mask_compressstoreu_epi16() as it's 256 uOps on Zen4 __m512i nnz = _mm512_maskz_compress_epi16(nnzMask, base); - _mm512_storeu_epi16(out + count, nnz); + _mm512_storeu_si512(out + count, nnz); count += popcount(nnzMask); base = _mm512_add_epi16(base, increment); From 2e91a8635468e40c89a2303ce50384864d088611 Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Sat, 9 Aug 2025 05:52:42 +0200 Subject: [PATCH 040/107] Add log depth as term to reduction factors. Replace most reduction factors with a linear term of the form X + Y * msb(depth) (using msb(depth) as simple and fast approximation for log(depth)) and tune the weights with following SPSA test: https://tests.stockfishchess.org/tests/view/689903860049e8ccef9d6415. Here the tuned values of X[8] and Y[8] were ignored because a simple test with this parameters alone failed badly (https://tests.stockfishchess.org/tests/view/68992b350049e8ccef9d6482). Passed STC: LLR: 2.95 (-2.94,2.94) <0.00,2.00> Total: 32448 W: 8651 L: 8342 D: 15455 Ptnml(0-2): 81, 3695, 8408, 3914, 126 https://tests.stockfishchess.org/tests/view/6899489b0049e8ccef9d64ad Passed LTC: LLR: 2.95 (-2.94,2.94) <0.50,2.50> Total: 73854 W: 19042 L: 18649 D: 36163 Ptnml(0-2): 37, 7908, 20659, 8271, 52 https://tests.stockfishchess.org/tests/view/689abbe7fd8719b088c8d514 closes https://github.com/official-stockfish/Stockfish/pull/6229 Bench: 3151102 --- src/search.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 3bf460a1a..b4b85ee76 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1178,27 +1178,27 @@ moves_loop: // When in check, search starts here // These reduction adjustments have no proven non-linear scaling - r += 650; // Base reduction offset to compensate for other tweaks - r -= moveCount * 69; + r += 679 - 6 * msb(depth); // Base reduction offset to compensate for other tweaks + r -= moveCount * (67 - 2 * msb(depth)); r -= std::abs(correctionValue) / 27160; // Increase reduction for cut nodes if (cutNode) - r += 3000 + 1024 * !ttData.move; + r += 2998 + 2 * msb(depth) + (948 + 14 * msb(depth)) * !ttData.move; // Increase reduction if ttMove is a capture if (ttCapture) - r += 1350; + r += 1402 - 39 * msb(depth); // Increase reduction if next ply has a lot of fail high if ((ss + 1)->cutoffCnt > 2) - r += 935 + allNode * 763; + r += 925 + 33 * msb(depth) + allNode * (701 + 224 * msb(depth)); r += (ss + 1)->quietMoveStreak * 51; // For first picked move (ttMove) reduce reduction if (move == ttData.move) - r -= 2043; + r -= 2121 + 28 * msb(depth); if (capture) ss->statScore = 782 * int(PieceValue[pos.captured_piece()]) / 128 @@ -1209,7 +1209,7 @@ moves_loop: // When in check, search starts here + (*contHist[1])[movedPiece][move.to_sq()]; // Decrease/increase reduction for moves with a good/bad history - r -= ss->statScore * 789 / 8192; + r -= ss->statScore * (729 - 12 * msb(depth)) / 8192; // Step 17. Late moves reduction / extension (LMR) if (depth >= 2 && moveCount > 1) @@ -1250,7 +1250,7 @@ moves_loop: // When in check, search starts here { // Increase reduction if ttMove is not present if (!ttData.move) - r += 1139; + r += 1199 + 35 * msb(depth); const int threshold1 = depth <= 4 ? 2000 : 3200; const int threshold2 = depth <= 4 ? 3500 : 4600; From d86414859519717c237570dbdea65de233a8d4f0 Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Sat, 9 Aug 2025 12:29:40 +0300 Subject: [PATCH 041/107] Simplify beta formula Passed STC: LLR: 2.93 (-2.94,2.94) <-1.75,0.25> Total: 152384 W: 39907 L: 39814 D: 72663 Ptnml(0-2): 557, 17958, 39053, 18083, 541 https://tests.stockfishchess.org/tests/view/6890b66692fcad741b804a10 Passed LTC: LLR: 2.95 (-2.94,2.94) <-1.75,0.25> Total: 98688 W: 25411 L: 25270 D: 48007 Ptnml(0-2): 45, 10692, 27743, 10805, 59 https://tests.stockfishchess.org/tests/view/6896019c618946ab878347b0 closes: https://github.com/official-stockfish/Stockfish/pull/6220 bench: 3002300 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index b4b85ee76..c81012625 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -369,7 +369,7 @@ void Search::Worker::iterative_deepening() { // otherwise exit the loop. if (bestValue <= alpha) { - beta = (3 * alpha + beta) / 4; + beta = alpha; alpha = std::max(bestValue - delta, -VALUE_INFINITE); failedHighCnt = 0; From 0db4a1bee9a7e1172dbcd105bc9f68b8f4817f86 Mon Sep 17 00:00:00 2001 From: Kevin Lu Date: Thu, 31 Jul 2025 14:17:07 -0700 Subject: [PATCH 042/107] Remove completedDepth condition for SE Just removing the term Passed STC: LLR: 3.27 (-2.94,2.94) <-1.75,0.25> Total: 179840 W: 47211 L: 47126 D: 85503 Ptnml(0-2): 567, 17929, 52879, 17942, 603 https://tests.stockfishchess.org/tests/view/688bdd88502b34dd5e7111ea Passed LTC: LLR: 3.26 (-2.94,2.94) <-1.75,0.25> Total: 150708 W: 38738 L: 38637 D: 73333 Ptnml(0-2): 79, 12922, 49262, 13001, 90 https://tests.stockfishchess.org/tests/view/688ce857f17748b4d23c8026 Passed VLTC: LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 288312 W: 74104 L: 74152 D: 140056 Ptnml(0-2): 44, 26732, 90657, 26674, 49 https://tests.stockfishchess.org/tests/view/688ec4f57d68fe4f7f130ee3 closes https://github.com/official-stockfish/Stockfish/pull/6221 functional at higher depths Bench: 3002300 --- AUTHORS | 1 + src/search.cpp | 5 ++--- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/AUTHORS b/AUTHORS index e606e5a8d..804824d8c 100644 --- a/AUTHORS +++ b/AUTHORS @@ -133,6 +133,7 @@ Justin Blanchard (UncombedCoconut) Kelly Wilson Ken Takusagawa Kenneth Lee (kennethlee33) +kevlu8 Kian E (KJE-98) kinderchocolate Kiran Panditrao (Krgp) diff --git a/src/search.cpp b/src/search.cpp index c81012625..b4569d9a5 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1112,9 +1112,8 @@ moves_loop: // When in check, search starts here // (*Scaler) Generally, higher singularBeta (i.e closer to ttValue) // and lower extension margins scale well. - if (!rootNode && move == ttData.move && !excludedMove - && depth >= 6 - (completedDepth > 26) + ss->ttPv && is_valid(ttData.value) - && !is_decisive(ttData.value) && (ttData.bound & BOUND_LOWER) + if (!rootNode && move == ttData.move && !excludedMove && depth >= 6 + ss->ttPv + && is_valid(ttData.value) && !is_decisive(ttData.value) && (ttData.bound & BOUND_LOWER) && ttData.depth >= depth - 3) { Value singularBeta = ttData.value - (56 + 79 * (ss->ttPv && !PvNode)) * depth / 58; From c9c002450a52f0b2315af65ebfb767024b33e136 Mon Sep 17 00:00:00 2001 From: Daniel Monroe Date: Sat, 9 Aug 2025 11:21:41 -0400 Subject: [PATCH 043/107] Simplify depth term in reductions Passed simplification STC LLR: 2.93 (-2.94,2.94) <-1.75,0.25> Total: 317344 W: 82352 L: 82442 D: 152550 Ptnml(0-2): 999, 37395, 81907, 37439, 932 https://tests.stockfishchess.org/tests/live_elo/68976798f8a258623dda6c46 Passed simplification LTC LLR: 2.97 (-2.94,2.94) <-1.75,0.25> Total: 291708 W: 74733 L: 74787 D: 142188 Ptnml(0-2): 159, 31813, 81956, 31775, 151 https://tests.stockfishchess.org/tests/live_elo/689791a5f8a258623dda6d03 closes https://github.com/official-stockfish/Stockfish/pull/6225 Bench: 2436991 --- src/search.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index b4569d9a5..6687ecb22 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1251,13 +1251,12 @@ moves_loop: // When in check, search starts here if (!ttData.move) r += 1199 + 35 * msb(depth); - const int threshold1 = depth <= 4 ? 2000 : 3200; - const int threshold2 = depth <= 4 ? 3500 : 4600; + if (depth <= 4) + r += 1150; // Note that if expected reduction is high, we reduce search depth here value = -search(pos, ss + 1, -(alpha + 1), -alpha, - newDepth - (r > threshold1) - (r > threshold2 && newDepth > 2), - !cutNode); + newDepth - (r > 3200) - (r > 4600 && newDepth > 2), !cutNode); } // For PV nodes only, do a full PV search on the first move or after a fail high, From 169737a9eb3edcb144e9c1db5d4555bd1e5934c0 Mon Sep 17 00:00:00 2001 From: Daniel Monroe Date: Sun, 10 Aug 2025 13:10:20 -0400 Subject: [PATCH 044/107] Simplify dual bonuses Merge dual capture/quiet bonuses into one Passed simplification STC LLR: 2.93 (-2.94,2.94) <-1.75,0.25> Total: 223200 W: 57868 L: 57854 D: 107478 Ptnml(0-2): 689, 26441, 57296, 26515, 659 https://tests.stockfishchess.org/tests/view/6898d28e0049e8ccef9d6384 Passed simplification LTC LLR: 2.95 (-2.94,2.94) <-1.75,0.25> Total: 147270 W: 37750 L: 37659 D: 71861 Ptnml(0-2): 84, 15869, 41633, 15970, 79 https://tests.stockfishchess.org/tests/view/68990fe30049e8ccef9d643c closes https://github.com/official-stockfish/Stockfish/pull/6226 Bench: 2996176 --- src/search.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 6687ecb22..aa78a673f 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1816,14 +1816,13 @@ void update_all_stats(const Position& pos, Piece movedPiece = pos.moved_piece(bestMove); PieceType capturedPiece; - int quietBonus = std::min(170 * depth - 87, 1598) + 332 * (bestMove == ttMove); + int bonus = std::min(170 * depth - 87, 1598) + 332 * (bestMove == ttMove); int quietMalus = std::min(743 * depth - 180, 2287) - 33 * quietsSearched.size(); - int captureBonus = std::min(124 * depth - 62, 1245) + 336 * (bestMove == ttMove); int captureMalus = std::min(708 * depth - 148, 2287) - 29 * capturesSearched.size(); if (!pos.capture_stage(bestMove)) { - update_quiet_histories(pos, ss, workerThread, bestMove, quietBonus * 978 / 1024); + update_quiet_histories(pos, ss, workerThread, bestMove, bonus * 978 / 1024); // Decrease stats for all non-best quiet moves for (Move move : quietsSearched) @@ -1833,7 +1832,7 @@ void update_all_stats(const Position& pos, { // Increase stats for the best move in case it was a capture move capturedPiece = type_of(pos.piece_on(bestMove.to_sq())); - captureHistory[movedPiece][bestMove.to_sq()][capturedPiece] << captureBonus * 1288 / 1024; + captureHistory[movedPiece][bestMove.to_sq()][capturedPiece] << bonus; } // Extra penalty for a quiet early move that was not a TT move in From 4b6b13ce5a76985ee00ad04d63164bd075b93720 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Sun, 17 Aug 2025 22:03:55 +0200 Subject: [PATCH 045/107] Update sde action to 2.4, switch to 9.33.0 older version no longer downloadable. closes https://github.com/official-stockfish/Stockfish/pull/6240 No functional change --- .github/ci/matrix.json | 4 ++-- .github/workflows/compilation.yml | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/ci/matrix.json b/.github/ci/matrix.json index 57c97686c..436cb4b84 100644 --- a/.github/ci/matrix.json +++ b/.github/ci/matrix.json @@ -8,7 +8,7 @@ "comp": "gcc", "shell": "bash", "archive_ext": "tar", - "sde": "/home/runner/work/Stockfish/Stockfish/.output/sde-temp-files/sde-external-9.27.0-2023-09-13-lin/sde -future --" + "sde": "/home/runner/work/Stockfish/Stockfish/.output/sde-temp-files/sde-external-9.33.0-2024-01-07-lin/sde -future --" }, { "name": "MacOS 13 Apple Clang", @@ -38,7 +38,7 @@ "msys_env": "x86_64-gcc", "shell": "msys2 {0}", "ext": ".exe", - "sde": "/d/a/Stockfish/Stockfish/.output/sde-temp-files/sde-external-9.27.0-2023-09-13-win/sde.exe -future --", + "sde": "/d/a/Stockfish/Stockfish/.output/sde-temp-files/sde-external-9.33.0-2024-01-07-win/sde.exe -future --", "archive_ext": "zip" }, { diff --git a/.github/workflows/compilation.yml b/.github/workflows/compilation.yml index 67b2e1c55..7805b24d6 100644 --- a/.github/workflows/compilation.yml +++ b/.github/workflows/compilation.yml @@ -43,10 +43,10 @@ jobs: - name: Download SDE package if: runner.os == 'Linux' || runner.os == 'Windows' - uses: petarpetrovt/setup-sde@91a1a03434384e064706634125a15f7446d2aafb # @v2.3 + uses: petarpetrovt/setup-sde@f0fa5971dc275704531e94264dd23250c442aa41 # @v2.4 with: environmentVariableName: SDE_DIR - sdeVersion: 9.27.0 + sdeVersion: 9.33.0 - name: Download the used network from the fishtest framework run: make net From c56bd10cb5ba192c76b6c5c6228625d58bd99892 Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Sat, 16 Aug 2025 13:40:48 +0200 Subject: [PATCH 046/107] Fix undefined behavior in stalemate trap detection. An important part of it is a function which detects if we can move a king or pawn. If this function called before quiet move generation phase the end of the checked move list is undefined (Thanks to AliceRoselia pointing out we have some problem because of wrong bench in a test). This problem exists also in master but is really rarely triggered (thanks to vondele which found one) but it seen significant more often if the capture order score is increased. This fix now simply assumes in this case (and other similiar cases) that a king or pawn can move without checking any moves. Passed non-regression STC (with default book): LLR: 3.03 (-2.94,2.94) <-1.75,0.25> Total: 203008 W: 52465 L: 52424 D: 98119 Ptnml(0-2): 498, 20293, 59893, 20310, 510 https://tests.stockfishchess.org/tests/view/68a06ec5fd8719b088c8dc1a Passed non-regression STC (with stalemates book): LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 31616 W: 14418 L: 14366 D: 2832 Ptnml(0-2): 1, 189, 15375, 243, 0 https://tests.stockfishchess.org/tests/view/68a07538fd8719b088c8dc1f closes https://github.com/official-stockfish/Stockfish/pull/6235 Bench: 2996176 --- src/movepick.cpp | 9 +++++++-- src/movepick.h | 2 +- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/src/movepick.cpp b/src/movepick.cpp index eb7c45837..dd6d71167 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -318,8 +318,13 @@ void MovePicker::skip_quiet_moves() { skipQuiets = true; } // this function must be called after all quiet moves and captures have been generated bool MovePicker::can_move_king_or_pawn() const { - // SEE negative captures shouldn't be returned in GOOD_CAPTURE stage - assert(stage > GOOD_CAPTURE && stage != EVASION_INIT); + + assert((GOOD_QUIET <= stage && stage <= BAD_QUIET) || stage == EVASION); + + // Until good capture state no quiet moves are generated for comparison so simply assume king or pawns can move. + // Do the same for other states that don't have a valid available move list. + if ((GOOD_QUIET > stage || stage > BAD_QUIET) && stage != EVASION) + return true; for (const ExtMove* m = moves; m < endGenerated; ++m) { diff --git a/src/movepick.h b/src/movepick.h index 9d6c02b0e..6a3305c6c 100644 --- a/src/movepick.h +++ b/src/movepick.h @@ -67,7 +67,7 @@ class MovePicker { const PieceToHistory** continuationHistory; const PawnHistory* pawnHistory; Move ttMove; - ExtMove * cur, *endCur, *endBadCaptures, *endCaptures, *endGenerated; + ExtMove * cur, *endCur, *endBadCaptures, *endCaptures, *endGenerated = moves; int stage; int threshold; Depth depth; From 2176c9387e24cb269e25126ef44dc53faef3cff1 Mon Sep 17 00:00:00 2001 From: 87 Date: Sat, 16 Aug 2025 22:41:55 +0100 Subject: [PATCH 047/107] Add performance warning comment for vpcompressw closes https://github.com/official-stockfish/Stockfish/pull/6237 No functional change --- src/movegen.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/movegen.cpp b/src/movegen.cpp index 10adc70be..697a83cdf 100644 --- a/src/movegen.cpp +++ b/src/movegen.cpp @@ -37,6 +37,7 @@ namespace { #if defined(USE_AVX512ICL) inline Move* write_moves(Move* moveList, uint32_t mask, __m512i vector) { + // Avoid _mm512_mask_compressstoreu_epi16() as it's 256 uOps on Zen4 _mm512_storeu_si512(reinterpret_cast<__m512i*>(moveList), _mm512_maskz_compress_epi16(mask, vector)); return moveList + popcount(mask); From 8ecfc3c89d48418f84864fb235635d69e6ea37b8 Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Sun, 17 Aug 2025 08:38:16 +0200 Subject: [PATCH 048/107] Bigger thread dependent initial window. Increase the initial delta of the aspiration window by "thread id mod 8". Passed SMP STC: LLR: 2.96 (-2.94,2.94) <0.00,2.00> Total: 106176 W: 27470 L: 27069 D: 51637 Ptnml(0-2): 121, 12032, 28386, 12423, 126 https://tests.stockfishchess.org/tests/view/68a178fab6fb3300203bbaec Passed SMP LTC: LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 133076 W: 34272 L: 33772 D: 65032 Ptnml(0-2): 38, 13709, 38537, 14223, 31 https://tests.stockfishchess.org/tests/view/68a1b5d2b6fb3300203bbb71 closes https://github.com/official-stockfish/Stockfish/pull/6239 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 aa78a673f..446f81379 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -322,7 +322,7 @@ void Search::Worker::iterative_deepening() { selDepth = 0; // Reset aspiration window starting size - delta = 5 + std::abs(rootMoves[pvIdx].meanSquaredScore) / 11131; + delta = 5 + threadIdx % 8 + std::abs(rootMoves[pvIdx].meanSquaredScore) / 11131; Value avg = rootMoves[pvIdx].averageScore; alpha = std::max(avg - delta, -VALUE_INFINITE); beta = std::min(avg + delta, VALUE_INFINITE); From 7fe46b5a70c7422e78bc0b484e772158b7fb4683 Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Sun, 17 Aug 2025 23:38:06 +0300 Subject: [PATCH 049/107] VVLTC tweak Passed VVLTC with STC bounds: LLR: 2.94 (-2.94,2.94) <0.00,2.00> Total: 60796 W: 15908 L: 15609 D: 29279 Ptnml(0-2): 6, 5598, 18889, 5901, 4 https://tests.stockfishchess.org/tests/view/68a1fbfeb6fb3300203bbc5c Passed VVLTC with LTC bounds: LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 24914 W: 6528 L: 6256 D: 12130 Ptnml(0-2): 4, 2263, 7648, 2541, 1 https://tests.stockfishchess.org/tests/view/68a211aeb6fb3300203bbca7 closes https://github.com/official-stockfish/Stockfish/pull/6241 Bench: 2130122 --- src/search.cpp | 215 +++++++++++++++++++++++++------------------------ 1 file changed, 108 insertions(+), 107 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 446f81379..e54f7c439 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -81,9 +81,9 @@ int correction_value(const Worker& w, const Position& pos, const Stack* const ss const auto bnpcv = w.nonPawnCorrectionHistory[non_pawn_index(pos)][BLACK][us]; const auto cntcv = m.is_ok() ? (*(ss - 2)->continuationCorrectionHistory)[pos.piece_on(m.to_sq())][m.to_sq()] - : 0; + : 8; - return 8867 * pcv + 8136 * micv + 10757 * (wnpcv + bnpcv) + 7232 * cntcv; + return 9536 * pcv + 8494 * micv + 10132 * (wnpcv + bnpcv) + 7156 * cntcv; } // Add correctionHistory value to raw staticEval and guarantee evaluation @@ -99,10 +99,10 @@ void update_correction_history(const Position& pos, const Move m = (ss - 1)->currentMove; const Color us = pos.side_to_move(); - static constexpr int nonPawnWeight = 165; + const int nonPawnWeight = 165; workerThread.pawnCorrectionHistory[pawn_correction_history_index(pos)][us] << bonus; - workerThread.minorPieceCorrectionHistory[minor_piece_index(pos)][us] << bonus * 153 / 128; + workerThread.minorPieceCorrectionHistory[minor_piece_index(pos)][us] << bonus * 145 / 128; workerThread.nonPawnCorrectionHistory[non_pawn_index(pos)][WHITE][us] << bonus * nonPawnWeight / 128; workerThread.nonPawnCorrectionHistory[non_pawn_index(pos)][BLACK][us] @@ -110,7 +110,7 @@ void update_correction_history(const Position& pos, if (m.is_ok()) (*(ss - 2)->continuationCorrectionHistory)[pos.piece_on(m.to_sq())][m.to_sq()] - << bonus * 153 / 128; + << bonus * 137 / 128; } // Add a small random component to draw evaluations to avoid 3-fold blindness @@ -286,7 +286,7 @@ void Search::Worker::iterative_deepening() { int searchAgainCounter = 0; - lowPlyHistory.fill(89); + lowPlyHistory.fill(97); // Iterative deepening loop until requested to stop or the target depth is reached while (++rootDepth < MAX_PLY && !threads.stop @@ -322,13 +322,13 @@ void Search::Worker::iterative_deepening() { selDepth = 0; // Reset aspiration window starting size - delta = 5 + threadIdx % 8 + std::abs(rootMoves[pvIdx].meanSquaredScore) / 11131; + delta = 5 + threadIdx % 8 + std::abs(rootMoves[pvIdx].meanSquaredScore) / 9000; Value avg = rootMoves[pvIdx].averageScore; alpha = std::max(avg - delta, -VALUE_INFINITE); beta = std::min(avg + delta, VALUE_INFINITE); // Adjust optimism based on root move's averageScore - optimism[us] = 136 * avg / (std::abs(avg) + 93); + optimism[us] = 137 * avg / (std::abs(avg) + 91); optimism[~us] = -optimism[us]; // Start with a small aspiration window and, in the case of a fail @@ -457,29 +457,29 @@ void Search::Worker::iterative_deepening() { rootMoves[0].effort * 100000 / std::max(size_t(1), size_t(nodes)); double fallingEval = - (11.396 + 2.035 * (mainThread->bestPreviousAverageScore - bestValue) - + 0.968 * (mainThread->iterValue[iterIdx] - bestValue)) + (11.325 + 2.115 * (mainThread->bestPreviousAverageScore - bestValue) + + 0.987 * (mainThread->iterValue[iterIdx] - bestValue)) / 100.0; - fallingEval = std::clamp(fallingEval, 0.5786, 1.6752); + fallingEval = std::clamp(fallingEval, 0.5688, 1.5698); // If the bestMove is stable over several iterations, reduce time accordingly - double k = 0.527; - double center = lastBestMoveDepth + 11; - timeReduction = 0.8 + 0.84 / (1.077 + std::exp(-k * (completedDepth - center))); + double k = 0.5189; + double center = lastBestMoveDepth + 11.57; + timeReduction = 0.723 + 0.79 / (1.104 + std::exp(-k * (completedDepth - center))); double reduction = - (1.4540 + mainThread->previousTimeReduction) / (2.1593 * timeReduction); - double bestMoveInstability = 0.9929 + 1.8519 * totBestMoveChanges / threads.size(); + (1.455 + mainThread->previousTimeReduction) / (2.2375 * timeReduction); + double bestMoveInstability = 1.04 + 1.8956 * totBestMoveChanges / threads.size(); double totalTime = mainThread->tm.optimum() * fallingEval * reduction * bestMoveInstability; // Cap used time in case of a single legal move for a better viewer experience if (rootMoves.size() == 1) - totalTime = std::min(500.0, totalTime); + totalTime = std::min(502.0, totalTime); auto elapsedTime = elapsed(); - if (completedDepth >= 10 && nodesEffort >= 97056 && elapsedTime > totalTime * 0.6540 + if (completedDepth >= 10 && nodesEffort >= 92425 && elapsedTime > totalTime * 0.666 && !mainThread->ponder) threads.stop = true; @@ -494,7 +494,7 @@ void Search::Worker::iterative_deepening() { threads.stop = true; } else - threads.increaseDepth = mainThread->ponder || elapsedTime <= totalTime * 0.5138; + threads.increaseDepth = mainThread->ponder || elapsedTime <= totalTime * 0.503; } mainThread->iterValue[iterIdx] = bestValue; @@ -544,9 +544,9 @@ void Search::Worker::undo_null_move(Position& pos) { pos.undo_null_move(); } // Reset histories, usually before a new game void Search::Worker::clear() { - mainHistory.fill(64); - captureHistory.fill(-753); - pawnHistory.fill(-1275); + mainHistory.fill(68); + captureHistory.fill(-689); + pawnHistory.fill(-1238); pawnCorrectionHistory.fill(5); minorPieceCorrectionHistory.fill(0); nonPawnCorrectionHistory.fill(0); @@ -561,10 +561,10 @@ void Search::Worker::clear() { for (StatsType c : {NoCaptures, Captures}) for (auto& to : continuationHistory[inCheck][c]) for (auto& h : to) - h.fill(-494); + h.fill(-529); for (size_t i = 1; i < reductions.size(); ++i) - reductions[i] = int(2782 / 128.0 * std::log(i)); + reductions[i] = int(2809 / 128.0 * std::log(i)); refreshTable.clear(networks[numaAccessToken]); } @@ -687,16 +687,16 @@ Value Search::Worker::search( // Bonus for a quiet ttMove that fails high if (!ttCapture) update_quiet_histories(pos, ss, *this, ttData.move, - std::min(127 * depth - 74, 1063)); + std::min(130 * depth - 71, 1043)); // Extra penalty for early quiet moves of the previous ply - if (prevSq != SQ_NONE && (ss - 1)->moveCount <= 3 && !priorCapture) - update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq, -2128); + if (prevSq != SQ_NONE && (ss - 1)->moveCount < 4 && !priorCapture) + update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq, -2142); } // Partial workaround for the graph history interaction problem // For high rule50 counts don't produce transposition table cutoffs. - if (pos.rule50_count() < 91) + if (pos.rule50_count() < 96) { if (depth >= 8 && ttData.move && pos.pseudo_legal(ttData.move) && pos.legal(ttData.move) && !is_decisive(ttData.value)) @@ -809,12 +809,12 @@ Value Search::Worker::search( // Use static evaluation difference to improve quiet move ordering if (((ss - 1)->currentMove).is_ok() && !(ss - 1)->inCheck && !priorCapture) { - int bonus = std::clamp(-10 * int((ss - 1)->staticEval + ss->staticEval), -1979, 1561) + 630; - mainHistory[~us][((ss - 1)->currentMove).from_to()] << bonus * 935 / 1024; + int bonus = std::clamp(-10 * int((ss - 1)->staticEval + ss->staticEval), -2023, 1563) + 583; + mainHistory[~us][((ss - 1)->currentMove).from_to()] << bonus * 944 / 1024; if (!ttHit && type_of(pos.piece_on(prevSq)) != PAWN && ((ss - 1)->currentMove).type_of() != PROMOTION) pawnHistory[pawn_history_index(pos)][pos.piece_on(prevSq)][prevSq] - << bonus * 1428 / 1024; + << bonus * 1438 / 1024; } // Set up the improving flag, which is true if current static evaluation is @@ -824,28 +824,28 @@ Value Search::Worker::search( improving = ss->staticEval > (ss - 2)->staticEval; opponentWorsening = ss->staticEval > -(ss - 1)->staticEval; - if (priorReduction >= (depth < 10 ? 1 : 3) && !opponentWorsening) + if (priorReduction >= (depth < 10 ? 2 : 3) && !opponentWorsening) depth++; - if (priorReduction >= 2 && depth >= 2 && ss->staticEval + (ss - 1)->staticEval > 177) + if (priorReduction >= 2 && depth >= 2 && ss->staticEval + (ss - 1)->staticEval > 173) depth--; // Step 7. Razoring // If eval is really low, skip search entirely and return the qsearch value. // For PvNodes, we must have a guard against mates being returned. - if (!PvNode && eval < alpha - 495 - 290 * depth * depth) + if (!PvNode && eval < alpha - 514 - 294 * depth * depth) return qsearch(pos, ss, alpha, beta); // Step 8. Futility pruning: child node // The depth condition is important for mate finding. { auto futility_margin = [&](Depth d) { - Value futilityMult = 90 - 20 * (cutNode && !ss->ttHit); + Value futilityMult = 91 - 21 * (!ss->ttHit); - return futilityMult * d // - - improving * futilityMult * 2 // - - opponentWorsening * futilityMult / 3 // - + (ss - 1)->statScore / 356 // - + std::abs(correctionValue) / 171290; + return futilityMult * d // + - 2094 * improving * futilityMult / 1024 // + - 1324 * opponentWorsening * futilityMult / 4096 // + + (ss - 1)->statScore / 331 // + + std::abs(correctionValue) / 158105; }; if (!ss->ttPv && depth < 14 && eval - futility_margin(depth) >= beta && eval >= beta @@ -854,13 +854,13 @@ Value Search::Worker::search( } // Step 9. Null move search with verification search - if (cutNode && ss->staticEval >= beta - 19 * depth + 403 && !excludedMove + if (cutNode && ss->staticEval >= beta - 18 * depth + 390 && !excludedMove && pos.non_pawn_material(us) && ss->ply >= nmpMinPly && !is_loss(beta)) { assert((ss - 1)->currentMove != Move::null()); // Null move dynamic reduction based on depth - Depth R = 7 + depth / 3; + Depth R = 6 + depth / 3; ss->currentMove = Move::null(); ss->continuationHistory = &continuationHistory[0][0][NO_PIECE][0]; @@ -904,7 +904,7 @@ Value Search::Worker::search( // Step 11. ProbCut // 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 + 215 - 60 * improving; + probCutBeta = beta + 224 - 64 * improving; if (depth >= 3 && !is_decisive(beta) // If value from transposition table is lower than probCutBeta, don't attempt @@ -914,7 +914,7 @@ Value Search::Worker::search( assert(probCutBeta < VALUE_INFINITE && probCutBeta > beta); MovePicker mp(pos, ttData.move, probCutBeta - ss->staticEval, &captureHistory); - Depth dynamicReduction = (ss->staticEval - beta) / 300; + Depth dynamicReduction = (ss->staticEval - beta) / 306; Depth probCutDepth = std::max(depth - 5 - dynamicReduction, 0); while ((move = mp.next_move()) != Move::none()) @@ -955,7 +955,7 @@ Value Search::Worker::search( moves_loop: // When in check, search starts here // Step 12. A small Probcut idea - probCutBeta = beta + 417; + probCutBeta = beta + 418; if ((ttData.bound & BOUND_LOWER) && ttData.depth >= depth - 4 && ttData.value >= probCutBeta && !is_decisive(beta) && is_valid(ttData.value) && !is_decisive(ttData.value)) return probCutBeta; @@ -1019,7 +1019,7 @@ moves_loop: // When in check, search starts here // Smaller or even negative value is better for short time controls // Bigger value is better for long time controls if (ss->ttPv) - r += 931; + r += 946; // Step 14. Pruning at shallow depth. // Depth conditions are important for mate finding. @@ -1041,15 +1041,15 @@ moves_loop: // When in check, search starts here if (!givesCheck && lmrDepth < 7 && !ss->inCheck) { - Value futilityValue = ss->staticEval + 232 + 224 * lmrDepth - + PieceValue[capturedPiece] + 131 * captHist / 1024; + Value futilityValue = ss->staticEval + 231 + 211 * lmrDepth + + PieceValue[capturedPiece] + 130 * captHist / 1024; if (futilityValue <= alpha) continue; } // SEE based pruning for captures and checks - int margin = std::clamp(158 * depth + captHist / 31, 0, 283 * depth); + int margin = std::clamp(157 * depth + captHist / 29, 0, 279 * depth); if (!pos.see_ge(move, -margin)) { bool mayStalemateTrap = @@ -1071,16 +1071,16 @@ moves_loop: // When in check, search starts here + pawnHistory[pawn_history_index(pos)][movedPiece][move.to_sq()]; // Continuation history based pruning - if (history < -4361 * depth) + if (history < -4312 * depth) continue; - history += 71 * mainHistory[us][move.from_to()] / 32; + history += 76 * mainHistory[us][move.from_to()] / 32; - lmrDepth += history / 3233; + lmrDepth += history / 3220; - Value baseFutility = (bestMove ? 46 : 230); + Value baseFutility = (bestMove ? 47 : 218); Value futilityValue = - ss->staticEval + baseFutility + 131 * lmrDepth + 91 * (ss->staticEval > alpha); + ss->staticEval + baseFutility + 134 * lmrDepth + 90 * (ss->staticEval > alpha); // Futility pruning: parent node // (*Scaler): Generally, more frequent futility pruning @@ -1096,7 +1096,7 @@ moves_loop: // When in check, search starts here lmrDepth = std::max(lmrDepth, 0); // Prune moves with negative SEE - if (!pos.see_ge(move, -26 * lmrDepth * lmrDepth)) + if (!pos.see_ge(move, -27 * lmrDepth * lmrDepth)) continue; } } @@ -1116,7 +1116,7 @@ moves_loop: // When in check, search starts here && is_valid(ttData.value) && !is_decisive(ttData.value) && (ttData.bound & BOUND_LOWER) && ttData.depth >= depth - 3) { - Value singularBeta = ttData.value - (56 + 79 * (ss->ttPv && !PvNode)) * depth / 58; + Value singularBeta = ttData.value - (56 + 81 * (ss->ttPv && !PvNode)) * depth / 60; Depth singularDepth = newDepth / 2; ss->excludedMove = move; @@ -1125,11 +1125,11 @@ moves_loop: // When in check, search starts here if (value < singularBeta) { - int corrValAdj = std::abs(correctionValue) / 249096; - int doubleMargin = 4 + 205 * PvNode - 223 * !ttCapture - corrValAdj - - 959 * ttMoveHistory / 131072 - (ss->ply > rootDepth) * 45; - int tripleMargin = 80 + 276 * PvNode - 249 * !ttCapture + 86 * ss->ttPv - corrValAdj - - (ss->ply * 2 > rootDepth * 3) * 53; + int corrValAdj = std::abs(correctionValue) / 229958; + int doubleMargin = -4 + 198 * PvNode - 212 * !ttCapture - corrValAdj + - 921 * ttMoveHistory / 127649 - (ss->ply > rootDepth) * 45; + int tripleMargin = 76 + 308 * PvNode - 250 * !ttCapture + 92 * ss->ttPv - corrValAdj + - (ss->ply * 2 > rootDepth * 3) * 52; extension = 1 + (value < singularBeta - doubleMargin) + (value < singularBeta - tripleMargin); @@ -1172,35 +1172,35 @@ moves_loop: // When in check, search starts here // Decrease reduction for PvNodes (*Scaler) if (ss->ttPv) - r -= 2510 + PvNode * 963 + (ttData.value > alpha) * 916 - + (ttData.depth >= depth) * (943 + cutNode * 1180); + r -= 2618 + PvNode * 991 + (ttData.value > alpha) * 903 + + (ttData.depth >= depth) * (978 + cutNode * 1051); // These reduction adjustments have no proven non-linear scaling - r += 679 - 6 * msb(depth); // Base reduction offset to compensate for other tweaks - r -= moveCount * (67 - 2 * msb(depth)); - r -= std::abs(correctionValue) / 27160; + r += 700 - 6 * msb(depth); // Base reduction offset to compensate for other tweaks + r -= moveCount * (64 - 2 * msb(depth)); + r -= std::abs(correctionValue) / 30450; // Increase reduction for cut nodes if (cutNode) - r += 2998 + 2 * msb(depth) + (948 + 14 * msb(depth)) * !ttData.move; + r += 3092 + 2 * msb(depth) + (980 + 15 * msb(depth)) * !ttData.move; // Increase reduction if ttMove is a capture if (ttCapture) - r += 1402 - 39 * msb(depth); + r += 1467 - 40 * msb(depth); // Increase reduction if next ply has a lot of fail high if ((ss + 1)->cutoffCnt > 2) - r += 925 + 33 * msb(depth) + allNode * (701 + 224 * msb(depth)); + r += 1041 + 34 * msb(depth) + allNode * (752 + 226 * msb(depth)); - r += (ss + 1)->quietMoveStreak * 51; + r += (ss + 1)->quietMoveStreak * 50; // For first picked move (ttMove) reduce reduction if (move == ttData.move) - r -= 2121 + 28 * msb(depth); + r -= 2096 + 27 * msb(depth); if (capture) - ss->statScore = 782 * int(PieceValue[pos.captured_piece()]) / 128 + ss->statScore = 803 * int(PieceValue[pos.captured_piece()]) / 128 + captureHistory[movedPiece][move.to_sq()][type_of(pos.captured_piece())]; else ss->statScore = 2 * mainHistory[us][move.from_to()] @@ -1208,7 +1208,7 @@ moves_loop: // When in check, search starts here + (*contHist[1])[movedPiece][move.to_sq()]; // Decrease/increase reduction for moves with a good/bad history - r -= ss->statScore * (729 - 12 * msb(depth)) / 8192; + r -= ss->statScore * (734 - 12 * msb(depth)) / 8192; // Step 17. Late moves reduction / extension (LMR) if (depth >= 2 && moveCount > 1) @@ -1218,7 +1218,8 @@ moves_loop: // When in check, search starts here // beyond the first move depth. // To prevent problems when the max value is less than the min value, // std::clamp has been replaced by a more robust implementation. - Depth d = std::max(1, std::min(newDepth - r / 1024, newDepth + 1 + PvNode)) + PvNode; + Depth d = + std::max(1, std::min(newDepth - r / 1024, newDepth + (PvNode ? 2 : 1))) + PvNode; ss->reduction = newDepth - d; value = -search(pos, ss + 1, -(alpha + 1), -alpha, d, true); @@ -1240,7 +1241,7 @@ moves_loop: // When in check, search starts here value = -search(pos, ss + 1, -(alpha + 1), -alpha, newDepth, !cutNode); // Post LMR continuation history updates - update_continuation_histories(ss, movedPiece, move.to_sq(), 1412); + update_continuation_histories(ss, movedPiece, move.to_sq(), 1365); } } @@ -1249,14 +1250,14 @@ moves_loop: // When in check, search starts here { // Increase reduction if ttMove is not present if (!ttData.move) - r += 1199 + 35 * msb(depth); + r += 1178 + 35 * msb(depth); - if (depth <= 4) - r += 1150; + if (depth < 5) + r += 1080; // Note that if expected reduction is high, we reduce search depth here value = -search(pos, ss + 1, -(alpha + 1), -alpha, - newDepth - (r > 3200) - (r > 4600 && newDepth > 2), !cutNode); + newDepth - (r > 3212) - (r > 4784 && newDepth > 2), !cutNode); } // For PV nodes only, do a full PV search on the first move or after a fail high, @@ -1361,7 +1362,7 @@ moves_loop: // When in check, search starts here } // Reduce other moves if we have found at least one score improvement - if (depth > 2 && depth < 16 && !is_decisive(value)) + if (depth > 2 && depth < 14 && !is_decisive(value)) depth -= 2; assert(depth > 0); @@ -1401,31 +1402,31 @@ moves_loop: // When in check, search starts here update_all_stats(pos, ss, *this, bestMove, prevSq, quietsSearched, capturesSearched, depth, ttData.move); if (!PvNode) - ttMoveHistory << (bestMove == ttData.move ? 811 : -848); + ttMoveHistory << (bestMove == ttData.move ? 809 : -865); } // Bonus for prior quiet countermove that caused the fail low else if (!priorCapture && prevSq != SQ_NONE) { - int bonusScale = -215; - bonusScale += std::min(-(ss - 1)->statScore / 103, 337); - bonusScale += std::min(64 * depth, 552); - bonusScale += 177 * ((ss - 1)->moveCount > 8); - bonusScale += 141 * (!ss->inCheck && bestValue <= ss->staticEval - 94); - bonusScale += 141 * (!(ss - 1)->inCheck && bestValue <= -(ss - 1)->staticEval - 76); + int bonusScale = -228; + bonusScale += std::min(-(ss - 1)->statScore / 104, 322); + bonusScale += std::min(63 * depth, 508); + bonusScale += 184 * ((ss - 1)->moveCount > 8); + bonusScale += 143 * (!ss->inCheck && bestValue <= ss->staticEval - 92); + bonusScale += 149 * (!(ss - 1)->inCheck && bestValue <= -(ss - 1)->staticEval - 70); bonusScale = std::max(bonusScale, 0); - const int scaledBonus = std::min(155 * depth - 88, 1416) * bonusScale; + const int scaledBonus = std::min(144 * depth - 92, 1365) * bonusScale; update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq, - scaledBonus * 397 / 32768); + scaledBonus * 400 / 32768); - mainHistory[~us][((ss - 1)->currentMove).from_to()] << scaledBonus * 224 / 32768; + mainHistory[~us][((ss - 1)->currentMove).from_to()] << scaledBonus * 220 / 32768; if (type_of(pos.piece_on(prevSq)) != PAWN && ((ss - 1)->currentMove).type_of() != PROMOTION) pawnHistory[pawn_history_index(pos)][pos.piece_on(prevSq)][prevSq] - << scaledBonus * 1127 / 32768; + << scaledBonus * 1164 / 32768; } // Bonus for prior capture countermove that caused the fail low @@ -1433,7 +1434,7 @@ moves_loop: // When in check, search starts here { Piece capturedPiece = pos.captured_piece(); assert(capturedPiece != NO_PIECE); - captureHistory[pos.piece_on(prevSq)][prevSq][type_of(capturedPiece)] << 1042; + captureHistory[pos.piece_on(prevSq)][prevSq][type_of(capturedPiece)] << 964; } if (PvNode) @@ -1644,11 +1645,11 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta) if (!capture && (*contHist[0])[pos.moved_piece(move)][move.to_sq()] + pawnHistory[pawn_history_index(pos)][pos.moved_piece(move)][move.to_sq()] - <= 5868) + <= 5475) continue; // Do not search moves with bad enough SEE values - if (!pos.see_ge(move, -74)) + if (!pos.see_ge(move, -78)) continue; } @@ -1721,7 +1722,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) const { int reductionScale = reductions[d] * reductions[mn]; - return reductionScale - delta * 731 / rootDelta + !i * reductionScale * 216 / 512 + 1089; + return reductionScale - delta * 757 / rootDelta + !i * reductionScale * 218 / 512 + 1200; } // elapsed() returns the time elapsed since the search started. If the @@ -1816,17 +1817,17 @@ void update_all_stats(const Position& pos, Piece movedPiece = pos.moved_piece(bestMove); PieceType capturedPiece; - int bonus = std::min(170 * depth - 87, 1598) + 332 * (bestMove == ttMove); - int quietMalus = std::min(743 * depth - 180, 2287) - 33 * quietsSearched.size(); - int captureMalus = std::min(708 * depth - 148, 2287) - 29 * capturesSearched.size(); + int bonus = std::min(151 * depth - 91, 1730) + 302 * (bestMove == ttMove); + int quietMalus = std::min(798 * depth - 175, 2268) - 33 * quietsSearched.size(); + int captureMalus = std::min(757 * depth - 134, 2129) - 28 * capturesSearched.size(); if (!pos.capture_stage(bestMove)) { - update_quiet_histories(pos, ss, workerThread, bestMove, bonus * 978 / 1024); + update_quiet_histories(pos, ss, workerThread, bestMove, bonus * 957 / 1024); // Decrease stats for all non-best quiet moves for (Move move : quietsSearched) - update_quiet_histories(pos, ss, workerThread, move, -quietMalus * 1115 / 1024); + update_quiet_histories(pos, ss, workerThread, move, -quietMalus * 1208 / 1024); } else { @@ -1839,14 +1840,14 @@ void update_all_stats(const Position& pos, // previous ply when it gets refuted. if (prevSq != SQ_NONE && ((ss - 1)->moveCount == 1 + (ss - 1)->ttHit) && !pos.captured_piece()) update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq, - -captureMalus * 622 / 1024); + -captureMalus * 594 / 1024); // Decrease stats for all non-best capture moves for (Move move : capturesSearched) { movedPiece = pos.moved_piece(move); capturedPiece = type_of(pos.piece_on(move.to_sq())); - captureHistory[movedPiece][move.to_sq()][capturedPiece] << -captureMalus * 1431 / 1024; + captureHistory[movedPiece][move.to_sq()][capturedPiece] << -captureMalus * 1366 / 1024; } } @@ -1854,8 +1855,8 @@ void update_all_stats(const Position& pos, // Updates histories of the move pairs formed 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) { - static constexpr std::array conthist_bonuses = { - {{1, 1108}, {2, 652}, {3, 273}, {4, 572}, {5, 126}, {6, 449}}}; + const std::array conthist_bonuses = { + {{1, 1157}, {2, 648}, {3, 288}, {4, 576}, {5, 140}, {6, 441}}}; for (const auto [i, weight] : conthist_bonuses) { @@ -1863,7 +1864,7 @@ void update_continuation_histories(Stack* ss, Piece pc, Square to, int bonus) { if (ss->inCheck && i > 2) break; if (((ss - i)->currentMove).is_ok()) - (*(ss - i)->continuationHistory)[pc][to] << (bonus * weight / 1024) + 80 * (i < 2); + (*(ss - i)->continuationHistory)[pc][to] << (bonus * weight / 1024) + 88 * (i < 2); } } @@ -1876,10 +1877,10 @@ void update_quiet_histories( workerThread.mainHistory[us][move.from_to()] << bonus; // Untuned to prevent duplicate effort if (ss->ply < LOW_PLY_HISTORY_SIZE) - workerThread.lowPlyHistory[ss->ply][move.from_to()] << (bonus * 771 / 1024) + 40; + workerThread.lowPlyHistory[ss->ply][move.from_to()] << (bonus * 741 / 1024) + 38; update_continuation_histories(ss, pos.moved_piece(move), move.to_sq(), - bonus * (bonus > 0 ? 979 : 842) / 1024); + bonus * (bonus > 0 ? 995 : 915) / 1024); int pIndex = pawn_history_index(pos); workerThread.pawnHistory[pIndex][pos.moved_piece(move)][move.to_sq()] From d11f49b790429c236a1a4169f0d8052635fc03dc Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Thu, 21 Aug 2025 18:23:49 +0200 Subject: [PATCH 050/107] Remove log depth reduction terms. Motivated by the elo loss of last VVLTC regression test i remove the new log depth reductions (tuned at STC) to regain strength at VVLTC. The constant terms are adjusted based on the old values and the changes from the last added VVLTC tuning. Passed VVLTC with STC bound: LLR: 2.95 (-2.94,2.94) <0.00,2.00> Total: 53802 W: 14030 L: 13740 D: 26032 Ptnml(0-2): 5, 4924, 16754, 5212, 6 https://tests.stockfishchess.org/tests/view/68a9a9f575da51a345a5a675 Passed VVLTC with LTC bound: LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 53658 W: 14022 L: 13699 D: 25937 Ptnml(0-2): 3, 4894, 16712, 5217, 3 https://tests.stockfishchess.org/tests/view/68a8d2b2b6fb3300203bca77 closes https://github.com/official-stockfish/Stockfish/pull/6257 Bench: 2566780 --- src/search.cpp | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index e54f7c439..286b339c0 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1177,27 +1177,27 @@ moves_loop: // When in check, search starts here // These reduction adjustments have no proven non-linear scaling - r += 700 - 6 * msb(depth); // Base reduction offset to compensate for other tweaks - r -= moveCount * (64 - 2 * msb(depth)); + r += 671; // Base reduction offset to compensate for other tweaks + r -= moveCount * 66; r -= std::abs(correctionValue) / 30450; // Increase reduction for cut nodes if (cutNode) - r += 3092 + 2 * msb(depth) + (980 + 15 * msb(depth)) * !ttData.move; + r += 3094 + 1056 * !ttData.move; // Increase reduction if ttMove is a capture if (ttCapture) - r += 1467 - 40 * msb(depth); + r += 1415; // Increase reduction if next ply has a lot of fail high if ((ss + 1)->cutoffCnt > 2) - r += 1041 + 34 * msb(depth) + allNode * (752 + 226 * msb(depth)); + r += 1051 + allNode * 814; r += (ss + 1)->quietMoveStreak * 50; // For first picked move (ttMove) reduce reduction if (move == ttData.move) - r -= 2096 + 27 * msb(depth); + r -= 2018; if (capture) ss->statScore = 803 * int(PieceValue[pos.captured_piece()]) / 128 @@ -1208,7 +1208,7 @@ moves_loop: // When in check, search starts here + (*contHist[1])[movedPiece][move.to_sq()]; // Decrease/increase reduction for moves with a good/bad history - r -= ss->statScore * (734 - 12 * msb(depth)) / 8192; + r -= ss->statScore * 794 / 8192; // Step 17. Late moves reduction / extension (LMR) if (depth >= 2 && moveCount > 1) @@ -1250,7 +1250,7 @@ moves_loop: // When in check, search starts here { // Increase reduction if ttMove is not present if (!ttData.move) - r += 1178 + 35 * msb(depth); + r += 1118; if (depth < 5) r += 1080; From 20bc19558e6ab9b5927d05227f6c29d577fa5960 Mon Sep 17 00:00:00 2001 From: Myself <63040919+AliceRoselia@users.noreply.github.com> Date: Sat, 23 Aug 2025 18:16:57 +0700 Subject: [PATCH 051/107] Speedup_threat_by_lesser This patch could have been considered a non-functional speedup, but changing the ranking of illegal moves. Passed STC: LLR: 2.95 (-2.94,2.94) <0.00,2.00> Total: 131040 W: 34247 L: 33792 D: 63001 Ptnml(0-2): 407, 15281, 33675, 15764, 393 https://tests.stockfishchess.org/tests/live_elo/68a9a75b75da51a345a5a66d Passed LTC: LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 280146 W: 72055 L: 71242 D: 136849 Ptnml(0-2): 153, 30252, 78438, 31089, 141 https://tests.stockfishchess.org/tests/view/68a9f58475da51a345a5a6e0 closes https://github.com/official-stockfish/Stockfish/pull/6261 Bench: 2321931 --- src/movepick.cpp | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/movepick.cpp b/src/movepick.cpp index dd6d71167..0d2a72306 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -129,13 +129,15 @@ ExtMove* MovePicker::score(MoveList& ml) { Color us = pos.side_to_move(); - [[maybe_unused]] Bitboard threatByLesser[QUEEN + 1]; + [[maybe_unused]] Bitboard threatByLesser[KING + 1]; if constexpr (Type == QUIETS) { + threatByLesser[PAWN] = 0; threatByLesser[KNIGHT] = threatByLesser[BISHOP] = pos.attacks_by(~us); threatByLesser[ROOK] = pos.attacks_by(~us) | pos.attacks_by(~us) | threatByLesser[KNIGHT]; threatByLesser[QUEEN] = pos.attacks_by(~us) | threatByLesser[ROOK]; + threatByLesser[KING] = pos.attacks_by(~us) | threatByLesser[QUEEN]; } ExtMove* it = cur; @@ -170,12 +172,10 @@ ExtMove* MovePicker::score(MoveList& ml) { // penalty for moving to a square threatened by a lesser piece // or bonus for escaping an attack by a lesser piece. - if (KNIGHT <= pt && pt <= QUEEN) - { - static constexpr int bonus[QUEEN + 1] = {0, 0, 144, 144, 256, 517}; - int v = threatByLesser[pt] & to ? -95 : 100 * bool(threatByLesser[pt] & from); - m.value += bonus[pt] * v; - } + static constexpr int bonus[KING + 1] = {0, 0, 144, 144, 256, 517, 10000}; + int v = threatByLesser[pt] & to ? -95 : 100 * bool(threatByLesser[pt] & from); + m.value += bonus[pt] * v; + if (ply < LOW_PLY_HISTORY_SIZE) m.value += 8 * (*lowPlyHistory)[ply][m.from_to()] / (1 + ply); From 176ef577e24e2346a6cc817079fe28b755fcdc8d Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Sun, 17 Aug 2025 23:54:09 +0300 Subject: [PATCH 052/107] Set back static constexpr closes https://github.com/official-stockfish/Stockfish/pull/6243 No functional change --- src/search.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 286b339c0..7068c332d 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -99,7 +99,7 @@ void update_correction_history(const Position& pos, const Move m = (ss - 1)->currentMove; const Color us = pos.side_to_move(); - const int nonPawnWeight = 165; + constexpr int nonPawnWeight = 165; workerThread.pawnCorrectionHistory[pawn_correction_history_index(pos)][us] << bonus; workerThread.minorPieceCorrectionHistory[minor_piece_index(pos)][us] << bonus * 145 / 128; @@ -839,7 +839,7 @@ Value Search::Worker::search( // The depth condition is important for mate finding. { auto futility_margin = [&](Depth d) { - Value futilityMult = 91 - 21 * (!ss->ttHit); + Value futilityMult = 91 - 21 * !ss->ttHit; return futilityMult * d // - 2094 * improving * futilityMult / 1024 // @@ -1855,7 +1855,7 @@ void update_all_stats(const Position& pos, // Updates histories of the move pairs formed 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) { - const std::array conthist_bonuses = { + static constexpr std::array conthist_bonuses = { {{1, 1157}, {2, 648}, {3, 288}, {4, 576}, {5, 140}, {6, 441}}}; for (const auto [i, weight] : conthist_bonuses) From 47d60a50b6b2704802641763335166c0b8a83453 Mon Sep 17 00:00:00 2001 From: Disservin Date: Tue, 19 Aug 2025 22:05:08 +0200 Subject: [PATCH 053/107] CI: fix typo in flag closes https://github.com/official-stockfish/Stockfish/pull/6247 No functional change --- .github/workflows/sanitizers.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/sanitizers.yml b/.github/workflows/sanitizers.yml index 950435f30..d9b783eb6 100644 --- a/.github/workflows/sanitizers.yml +++ b/.github/workflows/sanitizers.yml @@ -42,7 +42,7 @@ jobs: - name: Run with glibcxx assertions make_option: "" cxx_extra_flags: -D_GLIBCXX_ASSERTIONS - instrumented_option: non + instrumented_option: none defaults: run: working-directory: src From 57d76bd459a0c29f0932112d1ee432592054e1ce Mon Sep 17 00:00:00 2001 From: Daniel Monroe Date: Sun, 17 Aug 2025 17:20:08 -0400 Subject: [PATCH 054/107] Simplify depth condition in prior reduction Passed simplification STC LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 172864 W: 45085 L: 45015 D: 82764 Ptnml(0-2): 516, 20456, 44405, 20552, 503 https://tests.stockfishchess.org/tests/view/68a24791b6fb3300203bbdb6 Passed simplification LTC LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 84738 W: 21733 L: 21578 D: 41427 Ptnml(0-2): 49, 9169, 23780, 9320, 51 https://tests.stockfishchess.org/tests/view/68a2665ab6fb3300203bc269 closes https://github.com/official-stockfish/Stockfish/pull/6244 Bench: 2131292 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 7068c332d..f5fad184a 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -824,7 +824,7 @@ Value Search::Worker::search( improving = ss->staticEval > (ss - 2)->staticEval; opponentWorsening = ss->staticEval > -(ss - 1)->staticEval; - if (priorReduction >= (depth < 10 ? 2 : 3) && !opponentWorsening) + if (priorReduction >= 3 && !opponentWorsening) depth++; if (priorReduction >= 2 && depth >= 2 && ss->staticEval + (ss - 1)->staticEval > 173) depth--; From 2659351ce7c01b02528b6cf6c3553c571ccce962 Mon Sep 17 00:00:00 2001 From: Daniel Samek Date: Mon, 18 Aug 2025 06:33:51 +0200 Subject: [PATCH 055/107] Remove depth reduction in the full-depth search Passed simplification STC: LLR: 2.96 (-2.94,2.94) <-1.75,0.25> Total: 217184 W: 56218 L: 56195 D: 104771 Ptnml(0-2): 627, 25673, 55985, 25664, 643 https://tests.stockfishchess.org/tests/view/68a21e0eb6fb3300203bbcf3 Passed simplification LTC: LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 30474 W: 7923 L: 7713 D: 14838 Ptnml(0-2): 20, 3205, 8569, 3431, 12 https://tests.stockfishchess.org/tests/view/68a2adacb6fb3300203bc3f9 closes https://github.com/official-stockfish/Stockfish/pull/6246 bench 2626263 --- src/search.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index f5fad184a..47409b3a8 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1252,9 +1252,6 @@ moves_loop: // When in check, search starts here if (!ttData.move) r += 1118; - if (depth < 5) - r += 1080; - // Note that if expected reduction is high, we reduce search depth here value = -search(pos, ss + 1, -(alpha + 1), -alpha, newDepth - (r > 3212) - (r > 4784 && newDepth > 2), !cutNode); From 7fa7a36dc66792749eea2f1a24953ba27be19648 Mon Sep 17 00:00:00 2001 From: Daniel Monroe Date: Sun, 17 Aug 2025 17:09:09 -0400 Subject: [PATCH 056/107] Remove upper bound in see margin Passed simplification STC LLR: 2.93 (-2.94,2.94) <-1.75,0.25> Total: 99840 W: 25965 L: 25815 D: 48060 Ptnml(0-2): 326, 11708, 25688, 11886, 312 https://tests.stockfishchess.org/tests/view/68a24504b6fb3300203bbdae Passed simplification LTC LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 248388 W: 63544 L: 63556 D: 121288 Ptnml(0-2): 125, 27132, 69709, 27086, 142 https://tests.stockfishchess.org/tests/view/68a24f3bb6fb3300203bbdee closes https://github.com/official-stockfish/Stockfish/pull/6250 Bench: 2432765 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 47409b3a8..aafc33789 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1049,7 +1049,7 @@ moves_loop: // When in check, search starts here } // SEE based pruning for captures and checks - int margin = std::clamp(157 * depth + captHist / 29, 0, 279 * depth); + int margin = std::max(157 * depth + captHist / 29, 0); if (!pos.see_ge(move, -margin)) { bool mayStalemateTrap = From 85f87649bf70c68234b5f2dba33975690aece9f0 Mon Sep 17 00:00:00 2001 From: Shawn Xu Date: Wed, 20 Aug 2025 16:42:24 -0700 Subject: [PATCH 057/107] Simplify stalemate detection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Passed Non-regression STC: LLR: 2.96 (-2.94,2.94) <-1.75,0.25> Total: 107392 W: 27959 L: 27818 D: 51615 Ptnml(0-2): 317, 12094, 28735, 12231, 319 https://tests.stockfishchess.org/tests/view/68a65d8ab6fb3300203bc825 Passed Non-regression LTC: LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 94014 W: 24129 L: 23986 D: 45899 Ptnml(0-2): 47, 9917, 26934, 10064, 45 https://tests.stockfishchess.org/tests/view/68a8f45cb6fb3300203bcb5e Passed Stalemate 10k: Elo: 2.22 ± 1.3 (95%) LOS: 100.0% Total: 10000 W: 4626 L: 4562 D: 812 Ptnml(0-2): 1, 137, 4659, 203, 0 nElo: 12.00 ± 6.8 (95%) PairsRatio: 1.47 https://tests.stockfishchess.org/tests/view/68a65d8ab6fb3300203bc825 Supersedes #6114 Closes #6232 closes https://github.com/official-stockfish/Stockfish/pull/6255 Bench: 2473929 --- src/movepick.cpp | 19 ------------------- src/movepick.h | 1 - src/search.cpp | 3 +-- 3 files changed, 1 insertion(+), 22 deletions(-) diff --git a/src/movepick.cpp b/src/movepick.cpp index 0d2a72306..fa447e189 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -316,23 +316,4 @@ top: void MovePicker::skip_quiet_moves() { skipQuiets = true; } -// this function must be called after all quiet moves and captures have been generated -bool MovePicker::can_move_king_or_pawn() const { - - assert((GOOD_QUIET <= stage && stage <= BAD_QUIET) || stage == EVASION); - - // Until good capture state no quiet moves are generated for comparison so simply assume king or pawns can move. - // Do the same for other states that don't have a valid available move list. - if ((GOOD_QUIET > stage || stage > BAD_QUIET) && stage != EVASION) - return true; - - for (const ExtMove* m = moves; m < endGenerated; ++m) - { - PieceType movedPieceType = type_of(pos.moved_piece(*m)); - if ((movedPieceType == PAWN || movedPieceType == KING) && pos.legal(*m)) - return true; - } - return false; -} - } // namespace Stockfish diff --git a/src/movepick.h b/src/movepick.h index 6a3305c6c..922a9069b 100644 --- a/src/movepick.h +++ b/src/movepick.h @@ -50,7 +50,6 @@ class MovePicker { MovePicker(const Position&, Move, int, const CapturePieceToHistory*); Move next_move(); void skip_quiet_moves(); - bool can_move_king_or_pawn() const; private: template diff --git a/src/search.cpp b/src/search.cpp index aafc33789..1396a817d 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1056,8 +1056,7 @@ moves_loop: // When in check, search starts here depth > 2 && alpha < 0 && pos.non_pawn_material(us) == PieceValue[movedPiece] && PieceValue[movedPiece] >= RookValue // it can't be stalemate if we moved a piece adjacent to the king - && !(attacks_bb(pos.square(us)) & move.from_sq()) - && !mp.can_move_king_or_pawn(); + && !(attacks_bb(pos.square(us)) & move.from_sq()); // avoid pruning sacrifices of our last piece for stalemate if (!mayStalemateTrap) From 901ad7e7eed1d7166cc5a3b30da78001a5e686a7 Mon Sep 17 00:00:00 2001 From: Shawn Xu Date: Sat, 23 Aug 2025 06:29:45 -0700 Subject: [PATCH 058/107] Simplify quiet move streak Passed Non-regression STC: LLR: 2.93 (-2.94,2.94) <-1.75,0.25> Total: 46272 W: 12076 L: 11866 D: 22330 Ptnml(0-2): 140, 5407, 11860, 5561, 168 https://tests.stockfishchess.org/tests/view/68a9c26575da51a345a5a6a2 Passed Non-regression LTC: LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 140442 W: 35984 L: 35886 D: 68572 Ptnml(0-2): 72, 15333, 39305, 15447, 64 https://tests.stockfishchess.org/tests/view/68aa245e75da51a345a5a80d closes https://github.com/official-stockfish/Stockfish/pull/6258 Bench: 2931171 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 1396a817d..6a17e1624 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1006,7 +1006,7 @@ moves_loop: // When in check, search starts here movedPiece = pos.moved_piece(move); givesCheck = pos.gives_check(move); - (ss + 1)->quietMoveStreak = (!capture && !givesCheck) ? (ss->quietMoveStreak + 1) : 0; + (ss + 1)->quietMoveStreak = capture ? 0 : (ss->quietMoveStreak + 1); // Calculate new depth for this move newDepth = depth - 1; From e2fdf6f005bd772b6d376c8ddeb14b12760f73c2 Mon Sep 17 00:00:00 2001 From: Shawn Xu Date: Thu, 21 Aug 2025 21:05:42 -0700 Subject: [PATCH 059/107] Simplify separate malus formulas Passed Non-regression STC: LLR: 2.95 (-2.94,2.94) <-1.75,0.25> Total: 16352 W: 4336 L: 4090 D: 7926 Ptnml(0-2): 54, 1832, 4157, 2080, 53 https://tests.stockfishchess.org/tests/view/68a808f0b6fb3300203bca08 Passed Non-regression LTC: LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 94014 W: 24129 L: 23986 D: 45899 Ptnml(0-2): 47, 9917, 26934, 10064, 45 https://tests.stockfishchess.org/tests/view/68a8f45cb6fb3300203bcb5e closes https://github.com/official-stockfish/Stockfish/pull/6256 Bench: 2483704 --- src/search.cpp | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 6a17e1624..40e8ef7cf 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1813,9 +1813,8 @@ void update_all_stats(const Position& pos, Piece movedPiece = pos.moved_piece(bestMove); PieceType capturedPiece; - int bonus = std::min(151 * depth - 91, 1730) + 302 * (bestMove == ttMove); - int quietMalus = std::min(798 * depth - 175, 2268) - 33 * quietsSearched.size(); - int captureMalus = std::min(757 * depth - 134, 2129) - 28 * capturesSearched.size(); + int bonus = std::min(151 * depth - 91, 1730) + 302 * (bestMove == ttMove); + int malus = std::min(951 * depth - 156, 2468) - 30 * quietsSearched.size(); if (!pos.capture_stage(bestMove)) { @@ -1823,7 +1822,7 @@ void update_all_stats(const Position& pos, // Decrease stats for all non-best quiet moves for (Move move : quietsSearched) - update_quiet_histories(pos, ss, workerThread, move, -quietMalus * 1208 / 1024); + update_quiet_histories(pos, ss, workerThread, move, -malus); } else { @@ -1835,15 +1834,14 @@ void update_all_stats(const Position& pos, // Extra penalty for a quiet early move that was not a TT move in // previous ply when it gets refuted. if (prevSq != SQ_NONE && ((ss - 1)->moveCount == 1 + (ss - 1)->ttHit) && !pos.captured_piece()) - update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq, - -captureMalus * 594 / 1024); + update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq, -malus * 503 / 1024); // Decrease stats for all non-best capture moves for (Move move : capturesSearched) { movedPiece = pos.moved_piece(move); capturedPiece = type_of(pos.piece_on(move.to_sq())); - captureHistory[movedPiece][move.to_sq()][capturedPiece] << -captureMalus * 1366 / 1024; + captureHistory[movedPiece][move.to_sq()][capturedPiece] << -malus * 1157 / 1024; } } From af181d9fe11216a296113292f772561cfd9823d3 Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Sun, 24 Aug 2025 12:47:00 +0300 Subject: [PATCH 060/107] Small simplification in probCut movepicker Remove no longer required condition for tt moves. The idea is that if tt the value is greater than probCut beta try tt move that is a capture anyway - even if it doesn't pass SEE check. This idea in various implementations passed some STCs and was looking decent at LTCs as a gainer. Passed STC: https://tests.stockfishchess.org/tests/view/68aa1ee075da51a345a5a805 LLR: 2.93 (-2.94,2.94) <-1.75,0.25> Total: 136160 W: 35189 L: 35079 D: 65892 Ptnml(0-2): 436, 16083, 34891, 16275, 395 Passed LTC: https://tests.stockfishchess.org/tests/view/68aa91d375da51a345a5a884 LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 80022 W: 20652 L: 20492 D: 38878 Ptnml(0-2): 33, 8717, 22357, 8865, 39 closes https://github.com/official-stockfish/Stockfish/pull/6259 Bench: 2307940 --- src/movepick.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/movepick.cpp b/src/movepick.cpp index fa447e189..4b01beb67 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -115,8 +115,7 @@ MovePicker::MovePicker(const Position& p, Move ttm, int th, const CapturePieceTo threshold(th) { assert(!pos.checkers()); - stage = PROBCUT_TT - + !(ttm && pos.capture_stage(ttm) && pos.pseudo_legal(ttm) && pos.see_ge(ttm, threshold)); + stage = PROBCUT_TT + !(ttm && pos.capture_stage(ttm) && pos.pseudo_legal(ttm)); } // Assigns a numerical value to each move in a list, used for sorting. From c99eb8ef323dde5eafc2286590231e3d1594c9a3 Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Sun, 24 Aug 2025 14:02:03 +0300 Subject: [PATCH 061/107] Remove cap from a bonusScale formula Passed STC: LLR: 2.93 (-2.94,2.94) <-1.75,0.25> Total: 127264 W: 33159 L: 33042 D: 61063 Ptnml(0-2): 336, 14509, 33866, 14544, 377 https://tests.stockfishchess.org/tests/view/68a63fccb6fb3300203bc818 Passed LTC: LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 469512 W: 120094 L: 120331 D: 229087 Ptnml(0-2): 238, 51317, 131885, 51076, 240 https://tests.stockfishchess.org/tests/view/68a8d867b6fb3300203bcab5 closes https://github.com/official-stockfish/Stockfish/pull/6260 Bench: 2433974 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 40e8ef7cf..7704d530e 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1405,7 +1405,7 @@ moves_loop: // When in check, search starts here else if (!priorCapture && prevSq != SQ_NONE) { int bonusScale = -228; - bonusScale += std::min(-(ss - 1)->statScore / 104, 322); + bonusScale -= (ss - 1)->statScore / 104; bonusScale += std::min(63 * depth, 508); bonusScale += 184 * ((ss - 1)->moveCount > 8); bonusScale += 143 * (!ss->inCheck && bestValue <= ss->staticEval - 92); From 39c077f15a88ff1e563971c396eb9a27b0ac6ac5 Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Sun, 17 Aug 2025 20:05:43 +0200 Subject: [PATCH 062/107] Less reduction for later threads. Give "(thread id mod 8) * 64" less reductions (up to nearly a half ply). Passed SMP STC: LLR: 2.95 (-2.94,2.94) <0.00,2.00> Total: 413176 W: 106496 L: 105666 D: 201014 Ptnml(0-2): 504, 46732, 111266, 47602, 484 https://tests.stockfishchess.org/tests/view/68a24aeeb6fb3300203bbdc4 Passed SMP LTC: LLR: 2.95 (-2.94,2.94) <0.50,2.50> Total: 60420 W: 15622 L: 15268 D: 29530 Ptnml(0-2): 11, 6106, 17632, 6440, 21 https://tests.stockfishchess.org/tests/view/68a2c2ffb6fb3300203bc516 closes https://github.com/official-stockfish/Stockfish/pull/6249 No functional change --- src/search.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/search.cpp b/src/search.cpp index 7704d530e..d786b572a 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1177,6 +1177,7 @@ moves_loop: // When in check, search starts here // These reduction adjustments have no proven non-linear scaling r += 671; // Base reduction offset to compensate for other tweaks + r -= (threadIdx % 8) * 64; r -= moveCount * 66; r -= std::abs(correctionValue) / 30450; From 678d503d8f9c36e4087d7506f5d443c08f859c36 Mon Sep 17 00:00:00 2001 From: Shawn Xu Date: Sat, 23 Aug 2025 06:26:40 -0700 Subject: [PATCH 063/107] Simplify LMR Extensions Passed Non-regression STC: LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 236896 W: 61683 L: 61683 D: 113530 Ptnml(0-2): 730, 28057, 60901, 28003, 757 https://tests.stockfishchess.org/tests/view/68a9c20475da51a345a5a6a0 Passed Non-regression LTC: LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 73644 W: 18936 L: 18770 D: 35938 Ptnml(0-2): 33, 7951, 20685, 8123, 30 https://tests.stockfishchess.org/tests/view/68aa95c575da51a345a5a88a closes https://github.com/official-stockfish/Stockfish/pull/6265 Bench: 2693376 --- src/search.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index d786b572a..5f2f63c65 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1218,8 +1218,7 @@ moves_loop: // When in check, search starts here // beyond the first move depth. // To prevent problems when the max value is less than the min value, // std::clamp has been replaced by a more robust implementation. - Depth d = - std::max(1, std::min(newDepth - r / 1024, newDepth + (PvNode ? 2 : 1))) + PvNode; + Depth d = std::max(1, std::min(newDepth - r / 1024, newDepth + 2)) + PvNode; ss->reduction = newDepth - d; value = -search(pos, ss + 1, -(alpha + 1), -alpha, d, true); From cb7232a818d9994a5d122cf5e1af0d4915e265c0 Mon Sep 17 00:00:00 2001 From: Sebastian Buchwald Date: Sun, 24 Aug 2025 19:48:24 +0200 Subject: [PATCH 064/107] Use integer type for UCI spin values In particular, parse spin values as integers to avoid rounding errors. Fixes https://github.com/official-stockfish/Stockfish/issues/6263 closes https://github.com/official-stockfish/Stockfish/pull/6264 No functional change --- src/ucioption.cpp | 6 +++--- src/ucioption.h | 2 +- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ucioption.cpp b/src/ucioption.cpp index a76bd3ace..ff6235695 100644 --- a/src/ucioption.cpp +++ b/src/ucioption.cpp @@ -110,7 +110,7 @@ Option::Option(OnChange f) : max(0), on_change(std::move(f)) {} -Option::Option(double v, int minv, int maxv, OnChange f) : +Option::Option(int v, int minv, int maxv, OnChange f) : type("spin"), min(minv), max(maxv), @@ -154,7 +154,7 @@ Option& Option::operator=(const std::string& v) { if ((type != "button" && type != "string" && v.empty()) || (type == "check" && v != "true" && v != "false") - || (type == "spin" && (std::stof(v) < min || std::stof(v) > max))) + || (type == "spin" && (std::stoi(v) < min || std::stoi(v) > max))) return *this; if (type == "combo") @@ -202,7 +202,7 @@ std::ostream& operator<<(std::ostream& os, const OptionsMap& om) { } else if (o.type == "spin") - os << " default " << int(stof(o.defaultValue)) << " min " << o.min << " max " + os << " default " << stoi(o.defaultValue) << " min " << o.min << " max " << o.max; break; diff --git a/src/ucioption.h b/src/ucioption.h index 3d7386c30..0c957fda1 100644 --- a/src/ucioption.h +++ b/src/ucioption.h @@ -43,7 +43,7 @@ class Option { Option(OnChange = nullptr); Option(bool v, OnChange = nullptr); Option(const char* v, OnChange = nullptr); - Option(double v, int minv, int maxv, OnChange = nullptr); + Option(int v, int minv, int maxv, OnChange = nullptr); Option(const char* v, const char* cur, OnChange = nullptr); Option& operator=(const std::string&); From 69de394439265584e17caa497a31c48c1be0dc7a Mon Sep 17 00:00:00 2001 From: Akshat Sinha Date: Wed, 27 Aug 2025 20:36:01 +0530 Subject: [PATCH 065/107] fix ppc altivec check & loongarch64-lsx typo closes https://github.com/official-stockfish/Stockfish/pull/6276 No functional change --- scripts/get_native_properties.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/scripts/get_native_properties.sh b/scripts/get_native_properties.sh index e8c8f23f2..180c15d15 100755 --- a/scripts/get_native_properties.sh +++ b/scripts/get_native_properties.sh @@ -31,7 +31,7 @@ set_arch_loongarch64() { if check_flags 'lasx'; then true_arch='loongarch64-lasx' elif check_flags 'lsx'; then - true_arch='lonngarch64-lsx' + true_arch='loongarch64-lsx' else true_arch='loongarch64' fi @@ -57,7 +57,7 @@ set_arch_x86_64() { } set_arch_ppc_64() { - if $(grep -q -w "altivec" /proc/cpuinfo); then + if grep -q -w "altivec" /proc/cpuinfo; then power=$(grep -oP -m 1 'cpu\t+: POWER\K\d+' /proc/cpuinfo) if [ "0$power" -gt 7 ]; then # VSX started with POWER8 From 75f07da912577adbfab96f57716172cc972fe026 Mon Sep 17 00:00:00 2001 From: Nonlinear2 <131959792+Nonlinear2@users.noreply.github.com> Date: Mon, 25 Aug 2025 14:09:48 +0200 Subject: [PATCH 066/107] Avoid high rule50 count zeroing cutoffs If the depth is low enough, don't TT cut if the rule50 count is high and the TT move is zeroing. Passed STC: https://tests.stockfishchess.org/tests/view/68a8fdd8b6fb3300203bcb92 LLR: 3.05 (-2.94,2.94) <0.00,2.00> Total: 110304 W: 28805 L: 28402 D: 53097 Ptnml(0-2): 275, 11174, 31875, 11529, 299 Passed LTC: https://tests.stockfishchess.org/tests/view/68aa200f75da51a345a5a809 LLR: 3.00 (-2.94,2.94) <0.50,2.50> Total: 187956 W: 48489 L: 47928 D: 91539 Ptnml(0-2): 59, 16118, 61075, 16655, 71 closes https://github.com/official-stockfish/Stockfish/pull/6271 bench: 2641840 --- src/search.cpp | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 5f2f63c65..01155e260 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -679,7 +679,10 @@ Value Search::Worker::search( if (!PvNode && !excludedMove && ttData.depth > depth - (ttData.value <= beta) && is_valid(ttData.value) // Can happen when !ttHit or when access race in probe() && (ttData.bound & (ttData.value >= beta ? BOUND_LOWER : BOUND_UPPER)) - && (cutNode == (ttData.value >= beta) || depth > 5)) + && (cutNode == (ttData.value >= beta) || depth > 5) + // avoid a TT cutoff if the rule50 count is high and the TT move is zeroing + && (depth > 8 || ttData.move == Move::none() || pos.rule50_count() < 80 + || (!ttCapture && type_of(pos.moved_piece(ttData.move)) != PAWN))) { // If ttMove is quiet, update move sorting heuristics on TT hit if (ttData.move && ttData.value >= beta) From 222df615c1bbce15290d33f3f38d401a6df1743a Mon Sep 17 00:00:00 2001 From: "Robert Nurnberg @ elitebook" Date: Mon, 25 Aug 2025 11:09:39 +0200 Subject: [PATCH 067/107] revert #6259 The recent commit af181d9 was merged as a simplification, but unfortunately hurts mate finding efficiency. https://github.com/vondele/matetrack/blob/69f5c5e8627c163a6a8480b869ee09bc44dc44d4/matetrack1000000.csv#L4075-L4076 So this PR proposes to revert it, while adding a comment in the code for future reference. closes https://github.com/official-stockfish/Stockfish/pull/6269 Bench: 2566711 --- src/movepick.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/movepick.cpp b/src/movepick.cpp index 4b01beb67..b4523463f 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -115,7 +115,9 @@ MovePicker::MovePicker(const Position& p, Move ttm, int th, const CapturePieceTo threshold(th) { assert(!pos.checkers()); - stage = PROBCUT_TT + !(ttm && pos.capture_stage(ttm) && pos.pseudo_legal(ttm)); + // Removing the SEE check passes as simplification, but hurts mate finding + stage = PROBCUT_TT + + !(ttm && pos.capture_stage(ttm) && pos.pseudo_legal(ttm) && pos.see_ge(ttm, threshold)); } // Assigns a numerical value to each move in a list, used for sorting. From a289ee389aef03e4e2028f26aa472d82b909a892 Mon Sep 17 00:00:00 2001 From: Shawn Xu Date: Sun, 24 Aug 2025 02:02:31 -0700 Subject: [PATCH 068/107] Simplify Capture Futility Pruning Passed Non-regression STC: LLR: 2.97 (-2.94,2.94) <-1.75,0.25> Total: 187904 W: 48639 L: 48583 D: 90682 Ptnml(0-2): 560, 22150, 48502, 22154, 586 https://tests.stockfishchess.org/tests/view/68aad56075da51a345a5a9e3 Passed Non-regression LTC: LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 94302 W: 24246 L: 24101 D: 45955 Ptnml(0-2): 44, 10274, 26371, 10417, 45 https://tests.stockfishchess.org/tests/view/68ab541975da51a345a5aacf closes https://github.com/official-stockfish/Stockfish/pull/6266 Bench: 2376717 --- src/search.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 01155e260..41f650e79 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1041,9 +1041,8 @@ moves_loop: // When in check, search starts here int captHist = captureHistory[movedPiece][move.to_sq()][type_of(capturedPiece)]; // Futility pruning for captures - if (!givesCheck && lmrDepth < 7 && !ss->inCheck) + if (!givesCheck && lmrDepth < 7) { - Value futilityValue = ss->staticEval + 231 + 211 * lmrDepth + PieceValue[capturedPiece] + 130 * captHist / 1024; From 7d213afd37ff90bf1f6ca6deba5533f3f7fc51ff Mon Sep 17 00:00:00 2001 From: Shawn Xu Date: Sun, 24 Aug 2025 15:03:34 -0700 Subject: [PATCH 069/107] Non-functional simplifications closes https://github.com/official-stockfish/Stockfish/pull/6267 No functional change Co-authored-by: Daniel Monroe --- src/search.cpp | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 41f650e79..e7c5e6ac1 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -929,8 +929,6 @@ Value Search::Worker::search( assert(pos.capture_stage(move)); - movedPiece = pos.moved_piece(move); - do_move(pos, move, st, ss); // Perform a preliminary qsearch to verify that the move holds @@ -1079,9 +1077,8 @@ moves_loop: // When in check, search starts here lmrDepth += history / 3220; - Value baseFutility = (bestMove ? 47 : 218); - Value futilityValue = - ss->staticEval + baseFutility + 134 * lmrDepth + 90 * (ss->staticEval > alpha); + Value futilityValue = ss->staticEval + 47 + 171 * !bestMove + 134 * lmrDepth + + 90 * (ss->staticEval > alpha); // Futility pruning: parent node // (*Scaler): Generally, more frequent futility pruning @@ -1353,7 +1350,7 @@ moves_loop: // When in check, search starts here if (value >= beta) { - // (* Scaler) Especially if they make cutoffCnt increment more often. + // (*Scaler) Especially if they make cutoffCnt increment more often. ss->cutoffCnt += (extension < 2) || PvNode; assert(value >= beta); // Fail high break; From 3f183523963e4db27e6ac23394d78c11ef0fea40 Mon Sep 17 00:00:00 2001 From: Shawn Xu Date: Sun, 24 Aug 2025 11:09:31 -0700 Subject: [PATCH 070/107] Further Simplify Stalemate Detection MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Passed Non-regression STC: LLR: 2.98 (-2.94,2.94) <-1.75,0.25> Total: 191520 W: 49633 L: 49582 D: 92305 Ptnml(0-2): 557, 20676, 53260, 20693, 574 https://tests.stockfishchess.org/tests/view/68ab570075da51a345a5abe1 Passed Non-regression LTC: LLR: 2.96 (-2.94,2.94) <-1.75,0.25> Total: 212934 W: 54643 L: 54618 D: 103673 Ptnml(0-2): 117, 22417, 61364, 22462, 107 https://tests.stockfishchess.org/tests/view/68ab84e975da51a345a5ac6b 10k Stalemate: Elo: 0.35 ± 1.2 (95%) LOS: 71.6% Total: 10000 W: 4602 L: 4592 D: 806 Ptnml(0-2): 0, 148, 4694, 158, 0 nElo: 1.99 ± 6.8 (95%) PairsRatio: 1.07 https://tests.stockfishchess.org/tests/view/68abeb8175da51a345a5af82 closes https://github.com/official-stockfish/Stockfish/pull/6268 Bench: 2420973 --- src/movepick.h | 2 +- src/search.cpp | 5 +---- 2 files changed, 2 insertions(+), 5 deletions(-) diff --git a/src/movepick.h b/src/movepick.h index 922a9069b..5b3190594 100644 --- a/src/movepick.h +++ b/src/movepick.h @@ -66,7 +66,7 @@ class MovePicker { const PieceToHistory** continuationHistory; const PawnHistory* pawnHistory; Move ttMove; - ExtMove * cur, *endCur, *endBadCaptures, *endCaptures, *endGenerated = moves; + ExtMove * cur, *endCur, *endBadCaptures, *endCaptures, *endGenerated; int stage; int threshold; Depth depth; diff --git a/src/search.cpp b/src/search.cpp index e7c5e6ac1..de2ab7a3e 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1053,10 +1053,7 @@ moves_loop: // When in check, search starts here if (!pos.see_ge(move, -margin)) { bool mayStalemateTrap = - depth > 2 && alpha < 0 && pos.non_pawn_material(us) == PieceValue[movedPiece] - && PieceValue[movedPiece] >= RookValue - // it can't be stalemate if we moved a piece adjacent to the king - && !(attacks_bb(pos.square(us)) & move.from_sq()); + depth > 2 && alpha < 0 && pos.non_pawn_material(us) == PieceValue[movedPiece]; // avoid pruning sacrifices of our last piece for stalemate if (!mayStalemateTrap) From 6a6dadb5a63c1d62735b6ce6d7747ee56dc4680b Mon Sep 17 00:00:00 2001 From: Torsten Hellwig Date: Tue, 26 Aug 2025 10:30:33 +0200 Subject: [PATCH 071/107] Remove buggy and unused function The function does not fulfill its purpose and is not used anywhere. See https://discord.com/channels/435943710472011776/1101022188313772083/1409801409855094874 closes https://github.com/official-stockfish/Stockfish/pull/6275 no functional change --- src/position.h | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-) diff --git a/src/position.h b/src/position.h index cf6b1c472..56bb7b5a4 100644 --- a/src/position.h +++ b/src/position.h @@ -103,10 +103,9 @@ class Position { Square square(Color c) const; // Castling - CastlingRights castling_rights(Color c) const; - bool can_castle(CastlingRights cr) const; - bool castling_impeded(CastlingRights cr) const; - Square castling_rook_square(CastlingRights cr) const; + bool can_castle(CastlingRights cr) const; + bool castling_impeded(CastlingRights cr) const; + Square castling_rook_square(CastlingRights cr) const; // Checking Bitboard checkers() const; @@ -248,10 +247,6 @@ inline Square Position::ep_square() const { return st->epSquare; } inline bool Position::can_castle(CastlingRights cr) const { return st->castlingRights & cr; } -inline CastlingRights Position::castling_rights(Color c) const { - return c & CastlingRights(st->castlingRights); -} - inline bool Position::castling_impeded(CastlingRights cr) const { assert(cr == WHITE_OO || cr == WHITE_OOO || cr == BLACK_OO || cr == BLACK_OOO); return pieces() & castlingPath[cr]; From 7a3483fa9e618de10718c1888f61f82f83b955ef Mon Sep 17 00:00:00 2001 From: Sebastian Buchwald Date: Wed, 27 Aug 2025 22:32:09 +0200 Subject: [PATCH 072/107] Remove superfluous cast closes https://github.com/official-stockfish/Stockfish/pull/6277 No functional change --- src/position.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/position.cpp b/src/position.cpp index 4ac1369d4..f59632475 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -79,7 +79,7 @@ std::ostream& operator<<(std::ostream& os, const Position& pos) { for (Bitboard b = pos.checkers(); b;) os << UCIEngine::square(pop_lsb(b)) << " "; - if (int(Tablebases::MaxCardinality) >= popcount(pos.pieces()) && !pos.can_castle(ANY_CASTLING)) + if (Tablebases::MaxCardinality >= popcount(pos.pieces()) && !pos.can_castle(ANY_CASTLING)) { StateInfo st; From 731ad9bbc3332cb7c73ef9aa8797e38c9deee452 Mon Sep 17 00:00:00 2001 From: Arseniy Surkov <93079612+codedeliveryservice@users.noreply.github.com> Date: Fri, 29 Aug 2025 04:12:23 +0300 Subject: [PATCH 073/107] Simplify `adjust_key50` template Remove the AfterMove template from the adjust_key50 function, which is only ever called with false. closes https://github.com/official-stockfish/Stockfish/pull/6278 No functional change --- AUTHORS | 1 + src/position.h | 8 +++----- 2 files changed, 4 insertions(+), 5 deletions(-) diff --git a/AUTHORS b/AUTHORS index 804824d8c..6bd323d2c 100644 --- a/AUTHORS +++ b/AUTHORS @@ -32,6 +32,7 @@ Antoine Champion (antoinechampion) Aram Tumanian (atumanian) Arjun Temurnikar Aron Petkovski (fury) +Arseniy Surkov (codedeliveryservice) Artem Solopiy (EntityFX) Auguste Pop Balazs Szilagyi diff --git a/src/position.h b/src/position.h index 56bb7b5a4..dde496fe0 100644 --- a/src/position.h +++ b/src/position.h @@ -183,8 +183,7 @@ class Position { Square& rfrom, Square& rto, DirtyPiece* const dp = nullptr); - template - Key adjust_key50(Key k) const; + Key adjust_key50(Key k) const; // Data members Piece board[SQUARE_NB]; @@ -283,11 +282,10 @@ inline Bitboard Position::pinners(Color c) const { return st->pinners[c]; } inline Bitboard Position::check_squares(PieceType pt) const { return st->checkSquares[pt]; } -inline Key Position::key() const { return adjust_key50(st->key); } +inline Key Position::key() const { return adjust_key50(st->key); } -template inline Key Position::adjust_key50(Key k) const { - return st->rule50 < 14 - AfterMove ? k : k ^ make_key((st->rule50 - (14 - AfterMove)) / 8); + return st->rule50 < 14 ? k : k ^ make_key((st->rule50 - 14) / 8); } inline Key Position::pawn_key() const { return st->pawnKey; } From 38335838627107b0a9363b9b011c85b3c0a4bf19 Mon Sep 17 00:00:00 2001 From: Joost VandeVondele Date: Sun, 31 Aug 2025 11:35:30 +0200 Subject: [PATCH 074/107] limit dynamic reduction. fixes https://github.com/official-stockfish/Stockfish/issues/6280 prevents probcut from extending depth as analyzed here: https://github.com/official-stockfish/Stockfish/pull/6254#issuecomment-3239144280 passed STC: LLR: 2.93 (-2.94,2.94) <-1.75,0.25> Total: 86688 W: 22591 L: 22426 D: 41671 Ptnml(0-2): 305, 10125, 22311, 10306, 297 https://tests.stockfishchess.org/tests/view/68b418ab467ff96994ae4cd5 passed LTC: LLR: 2.95 (-2.94,2.94) <-1.75,0.25> Total: 82914 W: 21287 L: 21130 D: 40497 Ptnml(0-2): 39, 8959, 23305, 9114, 40 https://tests.stockfishchess.org/tests/view/68b47ffa78ed7a752a9e8f36 closes https://github.com/official-stockfish/Stockfish/pull/6286 Bench: 2787731 Co-Authored-By: xu-shawn <50402888+xu-shawn@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 de2ab7a3e..d2afc480b 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -917,7 +917,7 @@ Value Search::Worker::search( assert(probCutBeta < VALUE_INFINITE && probCutBeta > beta); MovePicker mp(pos, ttData.move, probCutBeta - ss->staticEval, &captureHistory); - Depth dynamicReduction = (ss->staticEval - beta) / 306; + Depth dynamicReduction = std::max((ss->staticEval - beta) / 306, -1); Depth probCutDepth = std::max(depth - 5 - dynamicReduction, 0); while ((move = mp.next_move()) != Move::none()) From da63060ea303bf18bd828114901c791d9061a944 Mon Sep 17 00:00:00 2001 From: Daniel Monroe Date: Wed, 27 Aug 2025 11:03:10 -0400 Subject: [PATCH 075/107] Simplify sign term in quiet histories Simplify sign term in quiet histories Passed simplification STC LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 497824 W: 129130 L: 129418 D: 239276 Ptnml(0-2): 1546, 59040, 128008, 58792, 1526 https://tests.stockfishchess.org/tests/view/68a2a9c1b6fb3300203bc3ed Passed simplification LTC LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 70830 W: 18185 L: 18016 D: 34629 Ptnml(0-2): 36, 7658, 19861, 7821, 39 https://tests.stockfishchess.org/tests/view/68af36c96217b8721dca98d9 closes https://github.com/official-stockfish/Stockfish/pull/6282 Bench: 2393762 --- src/search.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index d2afc480b..70124c589 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1869,8 +1869,7 @@ void update_quiet_histories( if (ss->ply < LOW_PLY_HISTORY_SIZE) workerThread.lowPlyHistory[ss->ply][move.from_to()] << (bonus * 741 / 1024) + 38; - update_continuation_histories(ss, pos.moved_piece(move), move.to_sq(), - bonus * (bonus > 0 ? 995 : 915) / 1024); + update_continuation_histories(ss, pos.moved_piece(move), move.to_sq(), bonus * 955 / 1024); int pIndex = pawn_history_index(pos); workerThread.pawnHistory[pIndex][pos.moved_piece(move)][move.to_sq()] From 75ac6c7a061a8f326d043b4454b15e16164885a6 Mon Sep 17 00:00:00 2001 From: Shawn Xu Date: Sun, 24 Aug 2025 21:03:20 -0700 Subject: [PATCH 076/107] simplify stalemate further MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Non-regression STC: LLR: 2.93 (-2.94,2.94) <-1.75,0.25> Total: 155200 W: 40650 L: 40562 D: 73988 Ptnml(0-2): 533, 17588, 41258, 17700, 521 https://tests.stockfishchess.org/tests/view/68abe11375da51a345a5adec Non-regression LTC: LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 82824 W: 21442 L: 21287 D: 40095 Ptnml(0-2): 51, 8738, 23675, 8901, 47 https://tests.stockfishchess.org/tests/view/68b205606217b8721dca9c8e 10k Stalemate: Elo: 1.46 ± 1.2 (95%) LOS: 99.0% Total: 10000 W: 4640 L: 4598 D: 762 Ptnml(0-2): 0, 140, 4678, 182, 0 https://tests.stockfishchess.org/tests/view/68b2059b6217b8721dca9c90 closes https://github.com/official-stockfish/Stockfish/pull/6283 Bench: 2431727 --- src/search.cpp | 13 ++++--------- 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 70124c589..634492682 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1049,16 +1049,11 @@ moves_loop: // When in check, search starts here } // SEE based pruning for captures and checks + // Avoid pruning sacrifices of our last piece for stalemate int margin = std::max(157 * depth + captHist / 29, 0); - if (!pos.see_ge(move, -margin)) - { - bool mayStalemateTrap = - depth > 2 && alpha < 0 && pos.non_pawn_material(us) == PieceValue[movedPiece]; - - // avoid pruning sacrifices of our last piece for stalemate - if (!mayStalemateTrap) - continue; - } + if ((alpha >= VALUE_DRAW || pos.non_pawn_material(us) != PieceValue[movedPiece]) + && !pos.see_ge(move, -margin)) + continue; } else { From f2da0ccf3f82c663daf958d05243d75247de6eb2 Mon Sep 17 00:00:00 2001 From: Shawn Xu Date: Sun, 24 Aug 2025 15:47:51 -0700 Subject: [PATCH 077/107] Simplify SMP Reduction Passed Non-regression SMP STC: LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 232784 W: 59845 L: 59841 D: 113098 Ptnml(0-2): 289, 26459, 62934, 26379, 331 https://tests.stockfishchess.org/tests/view/68ab96bf75da51a345a5acd6 Passed Non-regression SMP LTC: LLR: 2.95 (-2.94,2.94) <-1.75,0.25> Total: 374270 W: 95978 L: 96113 D: 182179 Ptnml(0-2): 118, 38575, 109888, 38432, 122 https://tests.stockfishchess.org/tests/view/68abcf1c75da51a345a5adb6 closes https://github.com/official-stockfish/Stockfish/pull/6285 Bench: 2667107 --- src/search.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 634492682..5a0185618 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1167,8 +1167,7 @@ moves_loop: // When in check, search starts here // These reduction adjustments have no proven non-linear scaling - r += 671; // Base reduction offset to compensate for other tweaks - r -= (threadIdx % 8) * 64; + r += 543; // Base reduction offset to compensate for other tweaks r -= moveCount * 66; r -= std::abs(correctionValue) / 30450; From adfddd2c984fac5f2ac02d87575af821ec118fa8 Mon Sep 17 00:00:00 2001 From: Shawn Xu Date: Sun, 31 Aug 2025 18:56:01 -0700 Subject: [PATCH 078/107] Add scaling note to STC/LTC tunes It has been repeatedly shown that such tunes are suspectible to become anti-scaling. Below are some recent examples: https://github.com/official-stockfish/Stockfish/commit/2e91a8635468e40c89a2303ce50384864d088611 https://github.com/official-stockfish/Stockfish/commit/d11f49b790429c236a1a4169f0d8052635fc03dc Passed STC: LLR: 2.95 (-2.94,2.94) <0.00,2.00> Total: 32448 W: 8651 L: 8342 D: 15455 Ptnml(0-2): 81, 3695, 8408, 3914, 126 https://tests.stockfishchess.org/tests/view/6899489b0049e8ccef9d64ad Passed LTC: LLR: 2.95 (-2.94,2.94) <0.50,2.50> Total: 73854 W: 19042 L: 18649 D: 36163 Ptnml(0-2): 37, 7908, 20659, 8271, 52 https://tests.stockfishchess.org/tests/view/689abbe7fd8719b088c8d514 Revert VVLTC with STC bound: LLR: 2.95 (-2.94,2.94) <0.00,2.00> Total: 53802 W: 14030 L: 13740 D: 26032 Ptnml(0-2): 5, 4924, 16754, 5212, 6 https://tests.stockfishchess.org/tests/view/68a9a9f575da51a345a5a675 Revert VVLTC with LTC bound: LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 53658 W: 14022 L: 13699 D: 25937 Ptnml(0-2): 3, 4894, 16712, 5217, 3 https://tests.stockfishchess.org/tests/view/68a8d2b2b6fb3300203bca77 https://tests.stockfishchess.org/tests/view/688cf38bf17748b4d23c8057 https://tests.stockfishchess.org/tests/view/6890bc7792fcad741b804a19 Passed LTC: LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 74928 W: 19466 L: 19071 D: 36391 Ptnml(0-2): 37, 8048, 20901, 8439, 39 Failed Non-regression VLTC: LLR: -2.94 (-2.94,2.94) <-1.75,0.25> Total: 57704 W: 14643 L: 14928 D: 28133 Ptnml(0-2): 5, 5925, 17280, 5634, 8 https://tests.stockfishchess.org/tests/view/6890bc7792fcad741b804a19 (Note that an STC-tuned version passed non-regression, but was shortly simplified) https://github.com/official-stockfish/Stockfish/pull/6040 Passed STC: LLR: 2.93 (-2.94,2.94) <0.00,2.00> Total: 27776 W: 7352 L: 7054 D: 13370 Ptnml(0-2): 68, 3126, 7221, 3386, 87 https://tests.stockfishchess.org/tests/view/680ec0f83629b02d74b1605b Passed LTC: LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 161304 W: 41432 L: 40864 D: 79008 Ptnml(0-2): 61, 17305, 45357, 17863, 66 https://tests.stockfishchess.org/tests/view/680ec7f93629b02d74b16084 Failed Non-regression VVLTC: LLR: -2.94 (-2.94,2.94) <-1.75,0.25> Total: 313466 W: 80573 L: 81089 D: 151804 Ptnml(0-2): 38, 29689, 97782, 29199, 25 https://tests.stockfishchess.org/tests/view/6810d0533629b02d74b16756 https://github.com/official-stockfish/Stockfish/pull/5907 https://github.com/official-stockfish/Stockfish/pull/5887 Passed LTC with STC bounds: https://tests.stockfishchess.org/tests/view/67b115dd6c6b9e172ad1592f LLR: 2.94 (-2.94,2.94) <0.00,2.00> Total: 75756 W: 19393 L: 19044 D: 37319 Ptnml(0-2): 60, 8251, 20913, 8588, 66 Passed LTC with LTC bounds: https://tests.stockfishchess.org/tests/view/67af5f5d6c6b9e172ad15765 LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 108126 W: 27880 L: 27412 D: 52834 Ptnml(0-2): 85, 11786, 29866, 12228, 98 Revert VVLTC w/ STC bounds: LLR: 2.94 (-2.94,2.94) <0.00,2.00> Total: 56342 W: 14536 L: 14246 D: 27560 Ptnml(0-2): 7, 5061, 17741, 5359, 3 https://tests.stockfishchess.org/tests/view/67be4f8ad8d5c2c657c52d10 Revert VVLTC w/ LTC bounds: LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 66562 W: 17364 L: 17016 D: 32182 Ptnml(0-2): 3, 6145, 20637, 6493, 3 https://tests.stockfishchess.org/tests/view/67bcd25ff6b602bd7222ea40 closes https://github.com/official-stockfish/Stockfish/pull/6284 no functional change --- src/search.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/search.cpp b/src/search.cpp index 5a0185618..40676e2e2 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -72,6 +72,9 @@ using SearchedList = ValueList; // so changing them or adding conditions that are similar requires // tests at these types of time controls. +// (*Scaler) All tuned parameters at time controls shorter than +// optimized for require verifications at longer time controls + int correction_value(const Worker& w, const Position& pos, const Stack* const ss) { const Color us = pos.side_to_move(); const auto m = (ss - 1)->currentMove; From d5f152b5df14bb27bbf2006f877dd9c5c51a8639 Mon Sep 17 00:00:00 2001 From: Shawn Xu Date: Tue, 2 Sep 2025 17:15:22 -0700 Subject: [PATCH 079/107] Reintroduce #6259 Reintroduces af181d9, which no longer regresses on matetrack after #6286 Using ./stockfish on matetrack.epd with --nodes 1000000 Engine ID: Stockfish dev-20250902-adfddd2c Total FENs: 6554 Found mates: 3490 Best mates: 2429 Passed Non-regression LTC: LLR: 2.95 (-2.94,2.94) <-1.75,0.25> Total: 37608 W: 9726 L: 9523 D: 18359 Ptnml(0-2): 16, 4001, 10578, 4182, 27 https://tests.stockfishchess.org/tests/view/68b886778f94a4e5a7fe77d9 closes https://github.com/official-stockfish/Stockfish/pull/6289 Bench: 2493363 --- src/movepick.cpp | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/movepick.cpp b/src/movepick.cpp index b4523463f..4b01beb67 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -115,9 +115,7 @@ MovePicker::MovePicker(const Position& p, Move ttm, int th, const CapturePieceTo threshold(th) { assert(!pos.checkers()); - // Removing the SEE check passes as simplification, but hurts mate finding - stage = PROBCUT_TT - + !(ttm && pos.capture_stage(ttm) && pos.pseudo_legal(ttm) && pos.see_ge(ttm, threshold)); + stage = PROBCUT_TT + !(ttm && pos.capture_stage(ttm) && pos.pseudo_legal(ttm)); } // Assigns a numerical value to each move in a list, used for sorting. From bfc7000597b8b5b0899e99bc911f6120a75c6297 Mon Sep 17 00:00:00 2001 From: Stefan Geschwentner Date: Sun, 24 Aug 2025 20:28:08 +0200 Subject: [PATCH 080/107] Adjustment of the aspiration window after fail high/low. For the new bound in the opposite direction of the fail, use a weighted average of alpha, beta and best value +- delta. In the case of a fail high, different average weights are used depending on whether or not there was a best move change during the last search. The weights are determined from the following two consecutive LTC tunings. First tuning: https://tests.stockfishchess.org/tests/view/68ab727975da51a345a5ac2e Second tuning: https://tests.stockfishchess.org/tests/view/68aba3fe75da51a345a5ad52 Passed LTC: LLR: 2.94 (-2.94,2.94) <0.00,2.00> Total: 39504 W: 10243 L: 9947 D: 19314 Ptnml(0-2): 25, 4182, 11041, 4480, 24 https://tests.stockfishchess.org/tests/view/68acbb6d6217b8721dca95f8 Passed VLTC: LLR: 2.95 (-2.94,2.94) <0.50,2.50> Total: 91196 W: 23574 L: 23167 D: 44455 Ptnml(0-2): 13, 8943, 27276, 9356, 10 https://tests.stockfishchess.org/tests/view/68af64786217b8721dca993d closes https://github.com/official-stockfish/Stockfish/pull/6292 Bench: 2785713 --- src/search.cpp | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 40676e2e2..9c4a94df8 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -344,7 +344,8 @@ void Search::Worker::iterative_deepening() { // effective increment for every four searchAgain steps (see issue #2717). Depth adjustedDepth = std::max(1, rootDepth - failedHighCnt - 3 * (searchAgainCounter + 1) / 4); - rootDelta = beta - alpha; + rootDelta = beta - alpha; + size_t previousBestMoveChanges = bestMoveChanges; bestValue = search(rootPos, ss, alpha, beta, adjustedDepth, false); // Bring the best move to the front. It is critical that sorting @@ -372,7 +373,9 @@ void Search::Worker::iterative_deepening() { // otherwise exit the loop. if (bestValue <= alpha) { - beta = alpha; + beta = + (alpha * 123 + beta * 9 + std::min(bestValue + delta, VALUE_INFINITE) * 12) + / 144; alpha = std::max(bestValue - delta, -VALUE_INFINITE); failedHighCnt = 0; @@ -381,6 +384,15 @@ void Search::Worker::iterative_deepening() { } else if (bestValue >= beta) { + if (bestMoveChanges > previousBestMoveChanges) + alpha = + (alpha * 116 + beta + std::max(bestValue - delta, -VALUE_INFINITE) * 7) + / 124; + else + alpha = (alpha * 119 + beta * 6 + + std::max(bestValue - delta, -VALUE_INFINITE) * 16) + / 141; + beta = std::min(bestValue + delta, VALUE_INFINITE); ++failedHighCnt; } From fc54d8730174cdb5cfc4f7074b90128e706e4040 Mon Sep 17 00:00:00 2001 From: Syine Mineta Date: Thu, 11 Sep 2025 13:53:40 +0900 Subject: [PATCH 081/107] Revert "Adjustment of the aspiration window after fail high/low." This reverts commit bfc7000597b8b5b0899e99bc911f6120a75c6297. Fixes https://github.com/official-stockfish/Stockfish/issues/6296 After this commit a bug has been reported when the position is close to mate or being mated. Since no workarounds have been suggested yet, it is best to revert this commit until a better solution is found. closes https://github.com/official-stockfish/Stockfish/pull/6309 Bench: 2493363 --- src/search.cpp | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 9c4a94df8..40676e2e2 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -344,8 +344,7 @@ void Search::Worker::iterative_deepening() { // effective increment for every four searchAgain steps (see issue #2717). Depth adjustedDepth = std::max(1, rootDepth - failedHighCnt - 3 * (searchAgainCounter + 1) / 4); - rootDelta = beta - alpha; - size_t previousBestMoveChanges = bestMoveChanges; + rootDelta = beta - alpha; bestValue = search(rootPos, ss, alpha, beta, adjustedDepth, false); // Bring the best move to the front. It is critical that sorting @@ -373,9 +372,7 @@ void Search::Worker::iterative_deepening() { // otherwise exit the loop. if (bestValue <= alpha) { - beta = - (alpha * 123 + beta * 9 + std::min(bestValue + delta, VALUE_INFINITE) * 12) - / 144; + beta = alpha; alpha = std::max(bestValue - delta, -VALUE_INFINITE); failedHighCnt = 0; @@ -384,15 +381,6 @@ void Search::Worker::iterative_deepening() { } else if (bestValue >= beta) { - if (bestMoveChanges > previousBestMoveChanges) - alpha = - (alpha * 116 + beta + std::max(bestValue - delta, -VALUE_INFINITE) * 7) - / 124; - else - alpha = (alpha * 119 + beta * 6 - + std::max(bestValue - delta, -VALUE_INFINITE) * 16) - / 141; - beta = std::min(bestValue + delta, VALUE_INFINITE); ++failedHighCnt; } From 1a3a9c90053f87c4b386efbb2e80153fd5b9a773 Mon Sep 17 00:00:00 2001 From: Disservin Date: Sun, 7 Sep 2025 12:41:02 +0200 Subject: [PATCH 082/107] simplify upload_binaries ci Previously the upload step used the os of the artifact to create the upload and used an extra msys2 step. This is in fact not needed and we can do all required changes on ubuntu instead. closes https://github.com/official-stockfish/Stockfish/pull/6294 No functional change --- .github/workflows/upload_binaries.yml | 18 ++++-------------- 1 file changed, 4 insertions(+), 14 deletions(-) diff --git a/.github/workflows/upload_binaries.yml b/.github/workflows/upload_binaries.yml index 1067f6e76..073e40a13 100644 --- a/.github/workflows/upload_binaries.yml +++ b/.github/workflows/upload_binaries.yml @@ -12,20 +12,17 @@ on: jobs: Artifacts: name: ${{ matrix.config.name }} ${{ matrix.binaries }} - runs-on: ${{ matrix.config.os }} + runs-on: ubuntu-latest env: - COMPCXX: ${{ matrix.config.compiler }} - COMP: ${{ matrix.config.comp }} EXT: ${{ matrix.config.ext }} NAME: ${{ matrix.config.simple_name }} BINARY: ${{ matrix.binaries }} - SDE: ${{ matrix.config.sde }} strategy: fail-fast: false matrix: ${{ fromJson(inputs.matrix) }} defaults: run: - shell: ${{ matrix.config.shell }} + shell: bash steps: - uses: actions/checkout@v4 with: @@ -37,13 +34,6 @@ jobs: name: ${{ matrix.config.simple_name }} ${{ matrix.binaries }} path: ${{ matrix.config.simple_name }} ${{ matrix.binaries }} - - name: Setup msys and install required packages - if: runner.os == 'Windows' - uses: msys2/setup-msys2@v2 - with: - msystem: ${{ matrix.config.msys_sys }} - install: mingw-w64-${{ matrix.config.msys_env }} make git zip - - name: Create Package run: | mkdir stockfish @@ -69,13 +59,13 @@ jobs: cp CONTRIBUTING.md ../stockfish/ - name: Create tar - if: runner.os != 'Windows' + if: ${{ !startsWith(matrix.config.os, 'windows') }} run: | chmod +x ./stockfish/stockfish-$NAME-$BINARY$EXT tar -cvf stockfish-$NAME-$BINARY.tar stockfish - name: Create zip - if: runner.os == 'Windows' + if: ${{ startsWith(matrix.config.os, 'windows') }} run: | zip -r stockfish-$NAME-$BINARY.zip stockfish From f922fb5d554b9f0d105f2b022a1028d76ad11b7e Mon Sep 17 00:00:00 2001 From: "Robert Nurnberg @ elitebook" Date: Sun, 7 Sep 2025 18:43:22 +0200 Subject: [PATCH 083/107] add multithreaded matetrack runs to CI Add runs with --threads 4 to our matetrack CI. These won't be deterministic, of course. But they may catch early some multithreading bugs in our mate reporting. Motivated by #6293 and #6296. https://github.com/official-stockfish/Stockfish/pull/6297 No functional change. --- .github/workflows/matetrack.yml | 39 ++++++++++++++++++++++++--------- 1 file changed, 29 insertions(+), 10 deletions(-) diff --git a/.github/workflows/matetrack.yml b/.github/workflows/matetrack.yml index 85c2be3e7..c4d14fc7b 100644 --- a/.github/workflows/matetrack.yml +++ b/.github/workflows/matetrack.yml @@ -47,25 +47,44 @@ jobs: wget --no-verbose -r -nH --cut-dirs=2 --no-parent --reject="index.html*" -e robots=off https://tablebase.lichess.ovh/tables/standard/3-4-5-wdl/ wget --no-verbose -r -nH --cut-dirs=2 --no-parent --reject="index.html*" -e robots=off https://tablebase.lichess.ovh/tables/standard/3-4-5-dtz/ - - name: Run matetrack + - name: Run matetrack th1 working-directory: matetrack run: | - python matecheck.py --syzygyPath 3-4-5-wdl/:3-4-5-dtz/ --engine /home/runner/work/Stockfish/Stockfish/Stockfish/src/stockfish --epdFile mates2000.epd --nodes 100000 | tee matecheckout.out - ! grep "issues were detected" matecheckout.out > /dev/null + python matecheck.py --syzygyPath 3-4-5-wdl/:3-4-5-dtz/ --engine /home/runner/work/Stockfish/Stockfish/Stockfish/src/stockfish --epdFile mates2000.epd --nodes 100000 | tee matecheckout1.out + ! grep "issues were detected" matecheckout1.out > /dev/null - - name: Run matetrack with --syzygy50MoveRule false + - name: Run matetrack th4 + working-directory: matetrack + run: | + python matecheck.py --syzygyPath 3-4-5-wdl/:3-4-5-dtz/ --engine /home/runner/work/Stockfish/Stockfish/Stockfish/src/stockfish --epdFile mates2000.epd --nodes 100000 --threads 4 | tee matecheckout4.out + ! grep "issues were detected" matecheckout4.out > /dev/null + + - name: Run matetrack th1 with --syzygy50MoveRule false working-directory: matetrack run: | grep 5men cursed.epd > cursed5.epd - python matecheck.py --syzygyPath 3-4-5-wdl/:3-4-5-dtz/ --engine /home/runner/work/Stockfish/Stockfish/Stockfish/src/stockfish --epdFile cursed5.epd --nodes 100000 --syzygy50MoveRule false | tee matecheckcursed.out - ! grep "issues were detected" matecheckcursed.out > /dev/null + python matecheck.py --syzygyPath 3-4-5-wdl/:3-4-5-dtz/ --engine /home/runner/work/Stockfish/Stockfish/Stockfish/src/stockfish --epdFile cursed5.epd --nodes 100000 --syzygy50MoveRule false | tee matecheckcursed1.out + ! grep "issues were detected" matecheckcursed1.out > /dev/null - - name: Verify mate and TB win count for matecheckcursed.out + - name: Run matetrack th4 with --syzygy50MoveRule false working-directory: matetrack run: | - mates=$(grep "Found mates:" matecheckcursed.out | awk '{print $3}') - tbwins=$(grep "Found TB wins:" matecheckcursed.out | awk '{print $4}') + grep 5men cursed.epd > cursed5.epd + python matecheck.py --syzygyPath 3-4-5-wdl/:3-4-5-dtz/ --engine /home/runner/work/Stockfish/Stockfish/Stockfish/src/stockfish --epdFile cursed5.epd --nodes 100000 --threads 4 --syzygy50MoveRule false | tee matecheckcursed4.out + ! grep "issues were detected" matecheckcursed4.out > /dev/null + + - name: Verify mate and TB win count for matecheckcursed[14].out + working-directory: matetrack + run: | + mates=$(grep "Found mates:" matecheckcursed1.out | awk '{print $3}') + tbwins=$(grep "Found TB wins:" matecheckcursed1.out | awk '{print $4}') if [ $(($mates + $tbwins)) -ne 32 ]; then - echo "Sum of mates and TB wins is not 32 in matecheckcursed.out" >&2 + echo "Sum of mates and TB wins is not 32 in matecheckcursed1.out" >&2 + exit 1 + fi + mates=$(grep "Found mates:" matecheckcursed4.out | awk '{print $3}') + tbwins=$(grep "Found TB wins:" matecheckcursed4.out | awk '{print $4}') + if [ $(($mates + $tbwins)) -ne 32 ]; then + echo "Sum of mates and TB wins is not 32 in matecheckcursed4.out" >&2 exit 1 fi From a82e2a4cb6154a985c1fbf61f74ab56bd097cc1c Mon Sep 17 00:00:00 2001 From: Sebastian Buchwald Date: Sat, 27 Sep 2025 20:35:20 +0200 Subject: [PATCH 084/107] Replace deprecated macOS 13 runner image The macOS 13 runner image will be retired by December 4th, 2025. closes https://github.com/official-stockfish/Stockfish/pull/6330 No functional change --- .github/ci/matrix.json | 22 +++++++++++----------- .github/workflows/tests.yml | 10 +++++----- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/.github/ci/matrix.json b/.github/ci/matrix.json index 436cb4b84..d916fd071 100644 --- a/.github/ci/matrix.json +++ b/.github/ci/matrix.json @@ -11,8 +11,8 @@ "sde": "/home/runner/work/Stockfish/Stockfish/.output/sde-temp-files/sde-external-9.33.0-2024-01-07-lin/sde -future --" }, { - "name": "MacOS 13 Apple Clang", - "os": "macos-13", + "name": "macOS 15 Apple Clang", + "os": "macos-15-intel", "simple_name": "macos", "compiler": "clang++", "comp": "clang", @@ -20,7 +20,7 @@ "archive_ext": "tar" }, { - "name": "MacOS 14 Apple Clang M1", + "name": "macOS 14 Apple Clang M1", "os": "macos-14", "simple_name": "macos-m1", "compiler": "clang++", @@ -126,31 +126,31 @@ { "binaries": "x86-64-avxvnni", "config": { - "os": "macos-13" + "os": "macos-15-intel" } }, { "binaries": "x86-64-avx512", "config": { - "os": "macos-13" + "os": "macos-15-intel" } }, { "binaries": "x86-64-vnni256", "config": { - "os": "macos-13" + "os": "macos-15-intel" } }, { "binaries": "x86-64-vnni512", "config": { - "os": "macos-13" + "os": "macos-15-intel" } }, { "binaries": "x86-64-avx512icl", "config": { - "os": "macos-13" + "os": "macos-15-intel" } }, { @@ -234,7 +234,7 @@ { "binaries": "apple-silicon", "config": { - "os": "macos-13" + "os": "macos-15-intel" } }, { @@ -258,7 +258,7 @@ { "binaries": "armv8", "config": { - "os": "macos-13" + "os": "macos-15-intel" } }, { @@ -288,7 +288,7 @@ { "binaries": "armv8-dotprod", "config": { - "os": "macos-13" + "os": "macos-15-intel" } }, { diff --git a/.github/workflows/tests.yml b/.github/workflows/tests.yml index 95ca12092..c2280f0b4 100644 --- a/.github/workflows/tests.yml +++ b/.github/workflows/tests.yml @@ -56,21 +56,21 @@ jobs: base_image: "ppc64le/alpine:latest" platform: linux/ppc64le shell: bash - - name: MacOS 13 Apple Clang - os: macos-13 + - name: macOS 15 Apple Clang + os: macos-15-intel compiler: clang++ comp: clang run_64bit_tests: true shell: bash - - name: MacOS 14 Apple Clang M1 + - name: macOS 14 Apple Clang M1 os: macos-14 compiler: clang++ comp: clang run_64bit_tests: false run_m1_tests: true shell: bash - - name: MacOS 13 GCC 11 - os: macos-13 + - name: macOS 15 GCC 11 + os: macos-15-intel compiler: g++-11 comp: gcc run_64bit_tests: true From a47a1c1804f1382c01b206442cf386435b446e99 Mon Sep 17 00:00:00 2001 From: Syine Mineta Date: Thu, 11 Sep 2025 09:00:01 +0900 Subject: [PATCH 085/107] Penalty to TT move history on MultiCut If a reduced search fails high with the TT move excluded, we know that there are multiple moves that can produce cutoffs. Applying a penalty to the TT move history reduces extensions for TT moves so that it may spend a bit more time exploring other moves. Passed STC: LLR: 2.93 (-2.94,2.94) <0.00,2.00> Total: 263680 W: 68965 L: 68313 D: 126402 Ptnml(0-2): 855, 31090, 67336, 31666, 893 https://tests.stockfishchess.org/tests/view/68c1f65a59efc3c96b6110e5 Passed LTC: LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 61008 W: 15713 L: 15350 D: 29945 Ptnml(0-2): 27, 6428, 17235, 6783, 31 https://tests.stockfishchess.org/tests/view/68c1fc5359efc3c96b611141 Passed non-regression VLTC (60+0.6, Threads=8): LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 50340 W: 13003 L: 12830 D: 24507 Ptnml(0-2): 3, 4570, 15849, 4747, 1 https://tests.stockfishchess.org/tests/view/68c2056559efc3c96b6111c3 closes https://github.com/official-stockfish/Stockfish/pull/6305 Bench: 2342975 --- src/search.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/search.cpp b/src/search.cpp index 40676e2e2..0a4a390bb 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1137,7 +1137,10 @@ moves_loop: // When in check, search starts here // singular (multiple moves fail high), and we can prune the whole // subtree by returning a softbound. else if (value >= beta && !is_decisive(value)) + { + ttMoveHistory << std::max(-400 - 100 * depth, -4000); return value; + } // Negative extensions // If other moves failed high over (ttValue - margin) without the From bbad001a4921e8351b42d6231b7d27c8c3ac9446 Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Thu, 11 Sep 2025 03:04:53 +0300 Subject: [PATCH 086/107] Double PawnHistory size and update formula Doubling PAWN_HISTORY_SIZE to 1024. So with that, we can apply a stronger learning signal. The bonus/malus multipliers in the update_quiet_histories function have been increased accordingly. Passed STC: LLR: 2.97 (-2.94,2.94) <0.00,2.00> Total: 111008 W: 29136 L: 28708 D: 53164 Ptnml(0-2): 367, 12870, 28609, 13284, 374 https://tests.stockfishchess.org/tests/view/68c201d659efc3c96b61117e Passed LTC: LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 117210 W: 30142 L: 29664 D: 57404 Ptnml(0-2): 49, 12532, 32970, 13000, 54 https://tests.stockfishchess.org/tests/view/68c20a6259efc3c96b6111ef closes https://github.com/official-stockfish/Stockfish/pull/6306 Bench: 2788334 --- src/history.h | 2 +- src/search.cpp | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/history.h b/src/history.h index faf4af3d7..1f7abc542 100644 --- a/src/history.h +++ b/src/history.h @@ -33,7 +33,7 @@ namespace Stockfish { -constexpr int PAWN_HISTORY_SIZE = 512; // has to be a power of 2 +constexpr int PAWN_HISTORY_SIZE = 1024; // has to be a power of 2 constexpr int CORRECTION_HISTORY_SIZE = 32768; // has to be a power of 2 constexpr int CORRECTION_HISTORY_LIMIT = 1024; constexpr int LOW_PLY_HISTORY_SIZE = 5; diff --git a/src/search.cpp b/src/search.cpp index 0a4a390bb..25102b131 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1873,7 +1873,7 @@ void update_quiet_histories( int pIndex = pawn_history_index(pos); workerThread.pawnHistory[pIndex][pos.moved_piece(move)][move.to_sq()] - << (bonus * (bonus > 0 ? 704 : 439) / 1024) + 70; + << (bonus * (bonus > 0 ? 800 : 500) / 1024) + 70; } } From 6fa42d9724b5bd21c5e20f578bb362be01afa0f5 Mon Sep 17 00:00:00 2001 From: Nonlinear2 <131959792+Nonlinear2@users.noreply.github.com> Date: Fri, 12 Sep 2025 21:03:50 +0200 Subject: [PATCH 087/107] Simplify RFP return value Passed non-regression STC: LLR: 2.96 (-2.94,2.94) <-1.75,0.25> Total: 220800 W: 57351 L: 57332 D: 106117 Ptnml(0-2): 726, 26200, 56548, 26181, 745 https://tests.stockfishchess.org/tests/view/68b1db6e6217b8721dca9c67 Passed gainer LTC: LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 257820 W: 66286 L: 65523 D: 126011 Ptnml(0-2): 118, 27586, 72779, 28269, 158 https://tests.stockfishchess.org/tests/view/68c1d40859efc3c96b610e3d closes https://github.com/official-stockfish/Stockfish/pull/6310 bench: 2364596 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 25102b131..fbf493486 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -856,7 +856,7 @@ Value Search::Worker::search( if (!ss->ttPv && depth < 14 && eval - futility_margin(depth) >= beta && eval >= beta && (!ttData.move || ttCapture) && !is_loss(beta) && !is_win(eval)) - return beta + (eval - beta) / 3; + return (2 * beta + eval) / 3; } // Step 9. Null move search with verification search From 4f4f78f86e8d44df2c13cfd6671f777dad516067 Mon Sep 17 00:00:00 2001 From: Michael Chaly Date: Sat, 20 Sep 2025 09:29:19 +0300 Subject: [PATCH 088/107] Extend nodes pre qsearch only with deep enough tt entries Modification of current pre qsearch extensions - allowing it only for deep enough tt entries. Passed STC: https://tests.stockfishchess.org/tests/view/68c954d302c43c969fe7eea5 LLR: 2.93 (-2.94,2.94) <0.00,2.00> Total: 35872 W: 9548 L: 9236 D: 17088 Ptnml(0-2): 101, 4075, 9295, 4341, 124 Passed LTC: https://tests.stockfishchess.org/tests/view/68ca4e4f02c43c969fe7ef5f LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 107754 W: 27784 L: 27324 D: 52646 Ptnml(0-2): 47, 11528, 30300, 11922, 80 closes https://github.com/official-stockfish/Stockfish/pull/6324 bench: 2462792 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index fbf493486..1ef01e5a6 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1260,7 +1260,7 @@ moves_loop: // When in check, search starts here (ss + 1)->pv[0] = Move::none(); // Extend move from transposition table if we are about to dive into qsearch. - if (move == ttData.move && rootDepth > 8) + if (move == ttData.move && ttData.depth > 1 && rootDepth > 8) newDepth = std::max(newDepth, 1); value = -search(pos, ss + 1, -beta, -alpha, newDepth, false); From 9b164d952061213da4fc0f7ac8646e44e8a77cd5 Mon Sep 17 00:00:00 2001 From: Timothy Herchen Date: Sat, 27 Sep 2025 08:40:42 -0700 Subject: [PATCH 089/107] Shave some instructions off a hot loop in affine transform On x86, GCC generates highly suboptimal code for this loop in its old form, about 2x as many instructions as necessary. This decreases throughput especially in an SMT setting. Clang does a better job but this change still has some improvement. Note that the std::ptrdiff_t type is not optional; using an unsigned type brings back the bad assembly. (Not sure why, but it seems reliable on all the GCC versions I tested.) passed STC: LLR: 2.93 (-2.94,2.94) <0.00,2.00> Total: 44672 W: 11841 L: 11527 D: 21304 Ptnml(0-2): 165, 4625, 12415, 4993, 138 https://tests.stockfishchess.org/tests/view/68d8111efa806e2e8393b10e closes https://github.com/official-stockfish/Stockfish/pull/6331 No functional change --- AUTHORS | 1 + src/nnue/layers/affine_transform_sparse_input.h | 17 ++++++++++++----- 2 files changed, 13 insertions(+), 5 deletions(-) diff --git a/AUTHORS b/AUTHORS index 6bd323d2c..1fb91adaf 100644 --- a/AUTHORS +++ b/AUTHORS @@ -243,6 +243,7 @@ Thanar2 thaspel theo77186 TierynnB +Timothy Herchen (anematode) Ting-Hsuan Huang (fffelix-huang) Tobias Steinmann Tomasz Sobczyk (Sopel97) diff --git a/src/nnue/layers/affine_transform_sparse_input.h b/src/nnue/layers/affine_transform_sparse_input.h index a073c6196..11e460666 100644 --- a/src/nnue/layers/affine_transform_sparse_input.h +++ b/src/nnue/layers/affine_transform_sparse_input.h @@ -22,6 +22,7 @@ #define NNUE_LAYERS_AFFINE_TRANSFORM_SPARSE_INPUT_H_INCLUDED #include +#include #include #include @@ -287,12 +288,18 @@ class AffineTransformSparseInput { for (IndexType k = 0; k < NumRegs; ++k) acc[k] = biasvec[k]; - for (IndexType j = 0; j < count; ++j) + auto* start = nnz; + auto* end = nnz + count; + + // convince GCC to not do weird pointer arithmetic in the following loop + const std::int8_t* weights_cp = weights; + + while (start < end) { - const auto i = nnz[j]; - const invec_t in = vec_set_32(input32[i]); - const auto col = - reinterpret_cast(&weights[i * OutputDimensions * ChunkSize]); + const std::ptrdiff_t i = *start; + start++; + const invec_t in = vec_set_32(input32[i]); + const auto col = (const invec_t*) (&weights_cp[i * OutputDimensions * ChunkSize]); for (IndexType k = 0; k < NumRegs; ++k) vec_add_dpbusd_32(acc[k], in, col[k]); } From 7a36c0e95fba5c544014b440fb2f35ef73e50393 Mon Sep 17 00:00:00 2001 From: Shawn Xu Date: Tue, 2 Sep 2025 14:10:11 -0700 Subject: [PATCH 090/107] Remove quiet move streak Passed Non-regression STC: LLR: 2.95 (-2.94,2.94) <-1.75,0.25> Total: 67712 W: 17744 L: 17555 D: 32413 Ptnml(0-2): 204, 8030, 17274, 8069, 279 https://tests.stockfishchess.org/tests/view/68b784628f94a4e5a7fe7706 Passed Non-regression LTC: LLR: 2.95 (-2.94,2.94) <-1.75,0.25> Total: 196050 W: 50270 L: 50228 D: 95552 Ptnml(0-2): 122, 21465, 54813, 21499, 126 https://tests.stockfishchess.org/tests/view/68ba119d8f94a4e5a7fe7941 closes https://github.com/official-stockfish/Stockfish/pull/6299 Bench: 2238789 Co-authored-by: Daniel Monroe --- src/search.cpp | 6 +----- src/search.h | 1 - 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 1ef01e5a6..9b6bbe188 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1010,8 +1010,6 @@ moves_loop: // When in check, search starts here movedPiece = pos.moved_piece(move); givesCheck = pos.gives_check(move); - (ss + 1)->quietMoveStreak = capture ? 0 : (ss->quietMoveStreak + 1); - // Calculate new depth for this move newDepth = depth - 1; @@ -1173,7 +1171,7 @@ moves_loop: // When in check, search starts here // These reduction adjustments have no proven non-linear scaling - r += 543; // Base reduction offset to compensate for other tweaks + r += 843; // Base reduction offset to compensate for other tweaks r -= moveCount * 66; r -= std::abs(correctionValue) / 30450; @@ -1189,8 +1187,6 @@ moves_loop: // When in check, search starts here if ((ss + 1)->cutoffCnt > 2) r += 1051 + allNode * 814; - r += (ss + 1)->quietMoveStreak * 50; - // For first picked move (ttMove) reduce reduction if (move == ttData.move) r -= 2018; diff --git a/src/search.h b/src/search.h index 07fc74317..d4bbca5c6 100644 --- a/src/search.h +++ b/src/search.h @@ -75,7 +75,6 @@ struct Stack { bool ttHit; int cutoffCnt; int reduction; - int quietMoveStreak; }; From 415a1ad42658dfc58ad1f6913f9dde6d069b37f3 Mon Sep 17 00:00:00 2001 From: Shawn Xu Date: Tue, 2 Sep 2025 13:10:00 -0700 Subject: [PATCH 091/107] Simplify Probcut Clamp Further Passed Non-regression STC: LLR: 2.93 (-2.94,2.94) <-1.75,0.25> Total: 157984 W: 41116 L: 41030 D: 75838 Ptnml(0-2): 568, 18570, 40601, 18714, 539 https://tests.stockfishchess.org/tests/view/68b750518f94a4e5a7fe76cd Passed Non-regression LTC: LLR: 2.95 (-2.94,2.94) <-1.75,0.25> Total: 335232 W: 85443 L: 85543 D: 164246 Ptnml(0-2): 177, 36616, 94137, 36502, 184 https://tests.stockfishchess.org/tests/view/68bc767259efc3c96b61076b closes https://github.com/official-stockfish/Stockfish/pull/6303 Bench: 2213844 --- src/search.cpp | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 9b6bbe188..888a8d870 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -920,8 +920,7 @@ Value Search::Worker::search( assert(probCutBeta < VALUE_INFINITE && probCutBeta > beta); MovePicker mp(pos, ttData.move, probCutBeta - ss->staticEval, &captureHistory); - Depth dynamicReduction = std::max((ss->staticEval - beta) / 306, -1); - Depth probCutDepth = std::max(depth - 5 - dynamicReduction, 0); + Depth probCutDepth = std::clamp(depth - 5 - (ss->staticEval - beta) / 306, 0, depth); while ((move = mp.next_move()) != Move::none()) { From 40aeb5a4118abc100987fab13a3329863b8d45c5 Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Thu, 11 Sep 2025 00:06:22 +0300 Subject: [PATCH 092/107] Simplify away conthist 0 While at it, I also added the scaler note to the Lmrdepth/history formula. Passed STC: LLR: 2.96 (-2.94,2.94) <-1.75,0.25> Total: 25376 W: 6660 L: 6423 D: 12293 Ptnml(0-2): 77, 2947, 6403, 3184, 77 https://tests.stockfishchess.org/tests/view/68c1ccf759efc3c96b610deb Passed LTC: LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 208464 W: 53371 L: 53342 D: 101751 Ptnml(0-2): 110, 22776, 58426, 22815, 105 https://tests.stockfishchess.org/tests/view/68c1d04b59efc3c96b610e13 closes https://github.com/official-stockfish/Stockfish/pull/6304 Bench: 2029296 --- src/search.cpp | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 888a8d870..13d86125a 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1067,6 +1067,7 @@ moves_loop: // When in check, search starts here history += 76 * mainHistory[us][move.from_to()] / 32; + // (*Scaler): Generally, a lower divisor scales well lmrDepth += history / 3220; Value futilityValue = ss->staticEval + 47 + 171 * !bestMove + 134 * lmrDepth @@ -1630,9 +1631,7 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta) // Continuation history based pruning if (!capture - && (*contHist[0])[pos.moved_piece(move)][move.to_sq()] - + pawnHistory[pawn_history_index(pos)][pos.moved_piece(move)][move.to_sq()] - <= 5475) + && pawnHistory[pawn_history_index(pos)][pos.moved_piece(move)][move.to_sq()] < 7300) continue; // Do not search moves with bad enough SEE values From c62e71e78f605bd66667289f2223429b3817eeab Mon Sep 17 00:00:00 2001 From: Shawn Xu Date: Wed, 10 Sep 2025 17:57:03 -0700 Subject: [PATCH 093/107] Simplify a separate term in low ply history bonus formula Passed Non-regression STC: LLR: 2.93 (-2.94,2.94) <-1.75,0.25> Total: 211200 W: 54887 L: 54860 D: 101453 Ptnml(0-2): 719, 24894, 54296, 25023, 668 https://tests.stockfishchess.org/tests/view/68c21e7f59efc3c96b6112c8 Passed Non-regression LTC: LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 217842 W: 55587 L: 55568 D: 106687 Ptnml(0-2): 130, 23651, 61313, 23724, 103 https://tests.stockfishchess.org/tests/view/68c230ec59efc3c96b61135a closes https://github.com/official-stockfish/Stockfish/pull/6307 Bench: 2070860 --- src/search.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/search.cpp b/src/search.cpp index 13d86125a..0684ea5cb 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1861,7 +1861,7 @@ void update_quiet_histories( workerThread.mainHistory[us][move.from_to()] << bonus; // Untuned to prevent duplicate effort if (ss->ply < LOW_PLY_HISTORY_SIZE) - workerThread.lowPlyHistory[ss->ply][move.from_to()] << (bonus * 741 / 1024) + 38; + workerThread.lowPlyHistory[ss->ply][move.from_to()] << bonus * 761 / 1024; update_continuation_histories(ss, pos.moved_piece(move), move.to_sq(), bonus * 955 / 1024); From 3073d82ccf25a8ab31e0e0215a2a661d0dcdadd7 Mon Sep 17 00:00:00 2001 From: Shawn Xu Date: Wed, 10 Sep 2025 20:17:08 -0700 Subject: [PATCH 094/107] Simplify use of low-ply history in evasions Passed Non-regression STC: LLR: 2.95 (-2.94,2.94) <-1.75,0.25> Total: 65024 W: 16991 L: 16804 D: 31229 Ptnml(0-2): 182, 7423, 17119, 7602, 186 https://tests.stockfishchess.org/tests/view/68c23f5459efc3c96b6113df Passed Non-regression LTC: LLR: 2.96 (-2.94,2.94) <-1.75,0.25> Total: 207312 W: 53126 L: 53095 D: 101091 Ptnml(0-2): 126, 21986, 59389, 22041, 114 https://tests.stockfishchess.org/tests/view/68c241e359efc3c96b6113ef closes https://github.com/official-stockfish/Stockfish/pull/6308 Bench: 2515619 --- src/movepick.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/movepick.cpp b/src/movepick.cpp index 4b01beb67..e7ac44c15 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -188,7 +188,7 @@ ExtMove* MovePicker::score(MoveList& ml) { { m.value = (*mainHistory)[us][m.from_to()] + (*continuationHistory[0])[pc][to]; if (ply < LOW_PLY_HISTORY_SIZE) - m.value += 2 * (*lowPlyHistory)[ply][m.from_to()] / (1 + ply); + m.value += 2 * (*lowPlyHistory)[ply][m.from_to()]; } } } From 5895f47dab6aee100bc274f870b275e20982a086 Mon Sep 17 00:00:00 2001 From: Shawn Xu Date: Wed, 10 Sep 2025 21:10:07 -0700 Subject: [PATCH 095/107] Further simplify low ply history in evasions Passed Non-regression STC (vs #6308): LLR: 2.96 (-2.94,2.94) <-1.75,0.25> Total: 174208 W: 45414 L: 45343 D: 83451 Ptnml(0-2): 633, 20324, 45095, 20443, 609 https://tests.stockfishchess.org/tests/view/68c24be359efc3c96b611487 Passed Non-regression LTC (vs #6308): LLR: 2.96 (-2.94,2.94) <-1.75,0.25> Total: 110070 W: 28099 L: 27969 D: 54002 Ptnml(0-2): 56, 11919, 30962, 12035, 63 https://tests.stockfishchess.org/tests/view/68c4efa559efc3c96b611dfc closes https://github.com/official-stockfish/Stockfish/pull/6321 Bench: 2151873 --- src/movepick.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/movepick.cpp b/src/movepick.cpp index e7ac44c15..2eec3556b 100644 --- a/src/movepick.cpp +++ b/src/movepick.cpp @@ -188,7 +188,7 @@ ExtMove* MovePicker::score(MoveList& ml) { { m.value = (*mainHistory)[us][m.from_to()] + (*continuationHistory[0])[pc][to]; if (ply < LOW_PLY_HISTORY_SIZE) - m.value += 2 * (*lowPlyHistory)[ply][m.from_to()]; + m.value += (*lowPlyHistory)[ply][m.from_to()]; } } } From 5c93616a3f7517c69eef55cdea67d6f04da63ce9 Mon Sep 17 00:00:00 2001 From: nicolasduhamel Date: Thu, 2 Oct 2025 20:17:32 +0200 Subject: [PATCH 096/107] Adjust aspiration window Narrow the aspiration window after fail high. Passed STC: LLR: 2.98 (-2.94,2.94) <0.00,2.00> Total: 51296 W: 13550 L: 13207 D: 24539 Ptnml(0-2): 165, 5971, 13052, 6276, 184 https://tests.stockfishchess.org/tests/view/68d99afffa806e2e8393b7ae Passed LTC; LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 87780 W: 22795 L: 22375 D: 42610 Ptnml(0-2): 52, 9340, 24694, 9744, 60 https://tests.stockfishchess.org/tests/view/68dae0a6fa806e2e8393baad See the comments in #6293 discussing the mechanisms leading to issue #6296 closes https://github.com/official-stockfish/Stockfish/pull/6337 Bench: 2336606 --- AUTHORS | 1 + src/search.cpp | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index 1fb91adaf..0429f9f0a 100644 --- a/AUTHORS +++ b/AUTHORS @@ -183,6 +183,7 @@ Nathan Rugg (nmrugg) Nguyen Pham (nguyenpham) Nicklas Persson (NicklasPersson) Nick Pelling (nickpelling) +Nicolas Duhamel (nikloskoda) Niklas Fiekas (niklasf) Nikolay Kostov (NikolayIT) Norman Schmidt (FireFather) diff --git a/src/search.cpp b/src/search.cpp index 0684ea5cb..04c04b5be 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -381,7 +381,8 @@ void Search::Worker::iterative_deepening() { } else if (bestValue >= beta) { - beta = std::min(bestValue + delta, VALUE_INFINITE); + alpha = std::max(beta - delta, alpha); + beta = std::min(bestValue + delta, VALUE_INFINITE); ++failedHighCnt; } else From 7a7c033a86be1c14817cfa1de2c85937585526b6 Mon Sep 17 00:00:00 2001 From: FauziAkram Date: Fri, 3 Oct 2025 01:39:39 +0300 Subject: [PATCH 097/107] Tweak Correction History Bonus Asymmetrically Refine the correction history update by applying an asymmetric bonus based on the type of evaluation error. It differentiates between negative corrections and positive corrections. Passed STC: LLR: 2.93 (-2.94,2.94) <0.00,2.00> Total: 165184 W: 43314 L: 42807 D: 79063 Ptnml(0-2): 551, 19391, 42261, 19778, 611 https://tests.stockfishchess.org/tests/view/68cae49902c43c969fe7f008 Passed LTC: LLR: 2.95 (-2.94,2.94) <0.50,2.50> Total: 243234 W: 62765 L: 62029 D: 118440 Ptnml(0-2): 163, 25996, 68551, 26756, 151 https://tests.stockfishchess.org/tests/view/68d1c50dfa806e2e8393aa1f closes https://github.com/official-stockfish/Stockfish/pull/6338 Bench: 2746404 --- src/search.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 04c04b5be..64f8ea189 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1449,9 +1449,11 @@ moves_loop: // When in check, search starts here && ((bestValue < ss->staticEval && bestValue < beta) // negative correction & no fail high || (bestValue > ss->staticEval && bestMove))) // positive correction & no fail low { - auto bonus = std::clamp(int(bestValue - ss->staticEval) * depth / 8, - -CORRECTION_HISTORY_LIMIT / 4, CORRECTION_HISTORY_LIMIT / 4); - update_correction_history(pos, ss, *this, bonus); + auto bonus = + std::clamp(int(bestValue - ss->staticEval) * depth / (8 + (bestValue > ss->staticEval)), + -CORRECTION_HISTORY_LIMIT / 4, CORRECTION_HISTORY_LIMIT / 4); + update_correction_history(pos, ss, *this, + (1088 - 180 * (bestValue > ss->staticEval)) * bonus / 1024); } assert(bestValue > -VALUE_INFINITE && bestValue < VALUE_INFINITE); From b09339a4205c3066fcddbae1490fb5f7a524d839 Mon Sep 17 00:00:00 2001 From: Timothy Herchen Date: Fri, 3 Oct 2025 12:41:21 -0700 Subject: [PATCH 098/107] Split accumulator 3-Way Squeeze a tiny bit more juice from the original idea in #6336 which this is on top of. https://tests.stockfishchess.org/tests/view/68dddd85fa806e2e8393c0b9 LLR: 2.95 (-2.94,2.94) <0.00,2.00> Total: 156320 W: 40925 L: 40447 D: 74948 Ptnml(0-2): 427, 17330, 42172, 17800, 431 4-way doesn't look to be better than this. https://tests.stockfishchess.org/tests/view/68dde19efa806e2e8393c0c1 closes https://github.com/official-stockfish/Stockfish/pull/6339 No functional change Co-authored-by: M Stembera --- .../layers/affine_transform_sparse_input.h | 53 +++++++++++++++---- 1 file changed, 43 insertions(+), 10 deletions(-) diff --git a/src/nnue/layers/affine_transform_sparse_input.h b/src/nnue/layers/affine_transform_sparse_input.h index 11e460666..effda826b 100644 --- a/src/nnue/layers/affine_transform_sparse_input.h +++ b/src/nnue/layers/affine_transform_sparse_input.h @@ -248,6 +248,7 @@ class AffineTransformSparseInput { #if defined(USE_AVX512) using invec_t = __m512i; using outvec_t = __m512i; + #define vec_add_32 _mm512_add_epi32 #define vec_set_32 _mm512_set1_epi32 #define vec_add_dpbusd_32 SIMD::m512_add_dpbusd_epi32 #elif defined(USE_AVX2) @@ -274,7 +275,16 @@ class AffineTransformSparseInput { static constexpr IndexType OutputSimdWidth = sizeof(outvec_t) / sizeof(OutputType); constexpr IndexType NumChunks = ceil_to_multiple(InputDimensions, 8) / ChunkSize; - constexpr IndexType NumRegs = OutputDimensions / OutputSimdWidth; + constexpr IndexType NumAccums = OutputDimensions / OutputSimdWidth; + // If there's only one accumulator and we're using high-latency dot product instructions, + // split it to create three separate dependency chains and merge at the end + constexpr bool SplitAccums = + #if defined(USE_VNNI) + NumAccums == 1; + #else + false; + #endif + constexpr IndexType NumRegs = SplitAccums ? 3 * NumAccums : NumAccums; std::uint16_t nnz[NumChunks]; IndexType count; @@ -285,27 +295,50 @@ class AffineTransformSparseInput { const outvec_t* biasvec = reinterpret_cast(biases); outvec_t acc[NumRegs]; - for (IndexType k = 0; k < NumRegs; ++k) + for (IndexType k = 0; k < NumAccums; ++k) acc[k] = biasvec[k]; - auto* start = nnz; - auto* end = nnz + count; + const auto* start = nnz; + const auto* end = nnz + count; // convince GCC to not do weird pointer arithmetic in the following loop const std::int8_t* weights_cp = weights; + if constexpr (SplitAccums) + { + acc[1] = acc[2] = vec_set_32(0); + while (start < end - 2) + { + const std::ptrdiff_t i0 = *start++; + const std::ptrdiff_t i1 = *start++; + const std::ptrdiff_t i2 = *start++; + const invec_t in0 = vec_set_32(input32[i0]); + const invec_t in1 = vec_set_32(input32[i1]); + const invec_t in2 = vec_set_32(input32[i2]); + const auto col0 = + reinterpret_cast(&weights_cp[i0 * OutputDimensions * ChunkSize]); + const auto col1 = + reinterpret_cast(&weights_cp[i1 * OutputDimensions * ChunkSize]); + const auto col2 = + reinterpret_cast(&weights_cp[i2 * OutputDimensions * ChunkSize]); + vec_add_dpbusd_32(acc[0], in0, *col0); + vec_add_dpbusd_32(acc[1], in1, *col1); + vec_add_dpbusd_32(acc[2], in2, *col2); + } + acc[0] = vec_add_32(vec_add_32(acc[0], acc[1]), acc[2]); + } while (start < end) { - const std::ptrdiff_t i = *start; - start++; - const invec_t in = vec_set_32(input32[i]); - const auto col = (const invec_t*) (&weights_cp[i * OutputDimensions * ChunkSize]); - for (IndexType k = 0; k < NumRegs; ++k) + const std::ptrdiff_t i = *start++; + const invec_t in = vec_set_32(input32[i]); + const auto col = + reinterpret_cast(&weights_cp[i * OutputDimensions * ChunkSize]); + for (IndexType k = 0; k < NumAccums; ++k) vec_add_dpbusd_32(acc[k], in, col[k]); } outvec_t* outptr = reinterpret_cast(output); - for (IndexType k = 0; k < NumRegs; ++k) + for (IndexType k = 0; k < NumAccums; ++k) outptr[k] = acc[k]; #undef vec_set_32 #undef vec_add_dpbusd_32 From e5c2dc5edd088fc614f0014219c8271840565c0c Mon Sep 17 00:00:00 2001 From: Shawn Xu Date: Mon, 29 Sep 2025 19:59:17 -0700 Subject: [PATCH 099/107] remove clang-format workaround closes https://github.com/official-stockfish/Stockfish/pull/6332 No functional change --- src/search.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 64f8ea189..6b2c28da2 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -585,10 +585,7 @@ Value Search::Worker::search( // Dive into quiescence search when the depth reaches zero if (depth <= 0) - { - constexpr auto nt = PvNode ? PV : NonPV; - return qsearch(pos, ss, alpha, beta); - } + return qsearch(pos, ss, alpha, beta); // Limit the depth if extensions made it too large depth = std::min(depth, MAX_PLY - 1); From ee243f0fdccd943fbba5a0eb5afa3531c23feffa Mon Sep 17 00:00:00 2001 From: mstembera Date: Sat, 4 Oct 2025 15:12:25 -0700 Subject: [PATCH 100/107] Remove x86-64-vnni256 target When vnni256 was first introduced #3038 it was very slightly faster than vnni512 on some machines. We have since sped up vnni512 significantly (#4796 over 10% alone, #6139, and probably others I'm forgetting). Since any machine that can run vnni256 can run vnni512 this arch is no longer useful. Note, x86-64-avxvnni still covers targets that don't have AVX512 but do have VNNI on 128- and 256-bit vectors. closes https://github.com/official-stockfish/Stockfish/pull/6340 No functional change --- .github/ci/matrix.json | 19 ------------------- scripts/get_native_properties.sh | 4 ++-- src/Makefile | 27 ++------------------------- 3 files changed, 4 insertions(+), 46 deletions(-) diff --git a/.github/ci/matrix.json b/.github/ci/matrix.json index d916fd071..f72451f5b 100644 --- a/.github/ci/matrix.json +++ b/.github/ci/matrix.json @@ -61,7 +61,6 @@ "x86-64-bmi2", "x86-64-avxvnni", "x86-64-avx512", - "x86-64-vnni256", "x86-64-vnni512", "x86-64-avx512icl", "apple-silicon", @@ -105,12 +104,6 @@ "os": "macos-14" } }, - { - "binaries": "x86-64-vnni256", - "config": { - "os": "macos-14" - } - }, { "binaries": "x86-64-vnni512", "config": { @@ -135,12 +128,6 @@ "os": "macos-15-intel" } }, - { - "binaries": "x86-64-vnni256", - "config": { - "os": "macos-15-intel" - } - }, { "binaries": "x86-64-vnni512", "config": { @@ -189,12 +176,6 @@ "os": "windows-11-arm" } }, - { - "binaries": "x86-64-vnni256", - "config": { - "os": "windows-11-arm" - } - }, { "binaries": "x86-64-vnni512", "config": { diff --git a/scripts/get_native_properties.sh b/scripts/get_native_properties.sh index 180c15d15..dec5998da 100755 --- a/scripts/get_native_properties.sh +++ b/scripts/get_native_properties.sh @@ -42,7 +42,7 @@ set_arch_x86_64() { if check_flags 'avx512f' 'avx512cd' 'avx512vl' 'avx512dq' 'avx512bw' 'avx512ifma' 'avx512vbmi' 'avx512vbmi2' 'avx512vpopcntdq' 'avx512bitalg' 'avx512vnni' 'vpclmulqdq' 'gfni' 'vaes'; then true_arch='x86-64-avx512icl' elif check_flags 'avx512vnni' 'avx512dq' 'avx512f' 'avx512bw' 'avx512vl'; then - true_arch='x86-64-vnni256' + true_arch='x86-64-vnni512' elif check_flags 'avx512f' 'avx512bw'; then true_arch='x86-64-avx512' elif [ -z "${znver_1_2+1}" ] && check_flags 'bmi2'; then @@ -83,7 +83,7 @@ case $uname_s in 'x86_64') flags=$(sysctl -n machdep.cpu.features machdep.cpu.leaf7_features | tr '\n' ' ' | tr '[:upper:]' '[:lower:]' | tr -d '_.') set_arch_x86_64 - if [ "$true_arch" = 'x86-64-vnni256' ] || [ "$true_arch" = 'x86-64-avx512' ]; then + if [ "$true_arch" = 'x86-64-avx512' ]; then file_arch='x86-64-bmi2' fi ;; diff --git a/src/Makefile b/src/Makefile index cec623f52..7244f7040 100644 --- a/src/Makefile +++ b/src/Makefile @@ -97,7 +97,6 @@ VPATH = syzygy:nnue:nnue/features # avx2 = yes/no --- -mavx2 --- Use Intel Advanced Vector Extensions 2 # avxvnni = yes/no --- -mavxvnni --- Use Intel Vector Neural Network Instructions AVX # avx512 = yes/no --- -mavx512bw --- Use Intel Advanced Vector Extensions 512 -# vnni256 = yes/no --- -mavx256vnni --- Use Intel Vector Neural Network Instructions 512 with 256bit operands # vnni512 = yes/no --- -mavx512vnni --- Use Intel Vector Neural Network Instructions 512 # avx512icl = yes/no --- ... multiple ... --- Use All AVX-512 features available on both Intel Ice Lake and AMD Zen 4 # altivec = yes/no --- -maltivec --- Use PowerPC Altivec SIMD extension @@ -128,7 +127,7 @@ endif # explicitly check for the list of supported architectures (as listed with make help), # the user can override with `make ARCH=x86-64-avx512icl SUPPORTED_ARCH=true` ifeq ($(ARCH), $(filter $(ARCH), \ - x86-64-avx512icl x86-64-vnni512 x86-64-vnni256 x86-64-avx512 x86-64-avxvnni \ + x86-64-avx512icl x86-64-vnni512 x86-64-avx512 x86-64-avxvnni \ x86-64-bmi2 x86-64-avx2 x86-64-sse41-popcnt x86-64-modern x86-64-ssse3 x86-64-sse3-popcnt \ x86-64 x86-32-sse41-popcnt x86-32-sse2 x86-32 ppc-64 ppc-64-altivec ppc-64-vsx ppc-32 e2k \ armv7 armv7-neon armv8 armv8-dotprod apple-silicon general-64 general-32 riscv64 \ @@ -153,7 +152,6 @@ sse41 = no avx2 = no avxvnni = no avx512 = no -vnni256 = no vnni512 = no avx512icl = no altivec = no @@ -269,17 +267,6 @@ ifeq ($(findstring -avx512,$(ARCH)),-avx512) avx512 = yes endif -ifeq ($(findstring -vnni256,$(ARCH)),-vnni256) - popcnt = yes - sse = yes - sse2 = yes - ssse3 = yes - sse41 = yes - avx2 = yes - pext = yes - vnni256 = yes -endif - ifeq ($(findstring -vnni512,$(ARCH)),-vnni512) popcnt = yes sse = yes @@ -724,17 +711,10 @@ ifeq ($(avx512),yes) endif endif -ifeq ($(vnni256),yes) - CXXFLAGS += -DUSE_VNNI - ifeq ($(comp),$(filter $(comp),gcc clang mingw icx)) - CXXFLAGS += -mavx512f -mavx512bw -mavx512vnni -mavx512dq -mavx512vl -mprefer-vector-width=256 - endif -endif - ifeq ($(vnni512),yes) CXXFLAGS += -DUSE_VNNI ifeq ($(comp),$(filter $(comp),gcc clang mingw icx)) - CXXFLAGS += -mavx512f -mavx512bw -mavx512vnni -mavx512dq -mavx512vl -mprefer-vector-width=512 + CXXFLAGS += -mavx512f -mavx512bw -mavx512vnni -mavx512dq -mavx512vl endif endif @@ -905,7 +885,6 @@ help: echo "native > select the best architecture for the host processor (default)" && \ echo "x86-64-avx512icl > x86 64-bit with minimum avx512 support of Intel Ice Lake or AMD Zen 4" && \ echo "x86-64-vnni512 > x86 64-bit with vnni 512bit support" && \ - echo "x86-64-vnni256 > x86 64-bit with vnni 512bit support, limit operands to 256bit wide" && \ echo "x86-64-avx512 > x86 64-bit with avx512 support" && \ echo "x86-64-avxvnni > x86 64-bit with vnni 256bit support" && \ echo "x86-64-bmi2 > x86 64-bit with bmi2 support" && \ @@ -1050,7 +1029,6 @@ config-sanity: net echo "avx2: '$(avx2)'" && \ echo "avxvnni: '$(avxvnni)'" && \ echo "avx512: '$(avx512)'" && \ - echo "vnni256: '$(vnni256)'" && \ echo "vnni512: '$(vnni512)'" && \ echo "avx512icl: '$(avx512icl)'" && \ echo "altivec: '$(altivec)'" && \ @@ -1087,7 +1065,6 @@ config-sanity: net (test "$(sse41)" = "yes" || test "$(sse41)" = "no") && \ (test "$(avx2)" = "yes" || test "$(avx2)" = "no") && \ (test "$(avx512)" = "yes" || test "$(avx512)" = "no") && \ - (test "$(vnni256)" = "yes" || test "$(vnni256)" = "no") && \ (test "$(vnni512)" = "yes" || test "$(vnni512)" = "no") && \ (test "$(avx512icl)" = "yes" || test "$(avx512icl)" = "no") && \ (test "$(altivec)" = "yes" || test "$(altivec)" = "no") && \ From feb17e5acfc6eec264628db7b1531db6fc94a3e4 Mon Sep 17 00:00:00 2001 From: Daniel Monroe Date: Mon, 6 Oct 2025 04:47:37 -0400 Subject: [PATCH 101/107] Make sure we don't move a nonexistent piece in SEE added assert. closes https://github.com/official-stockfish/Stockfish/pull/6342 No functional change --- src/position.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/position.cpp b/src/position.cpp index f59632475..d0cad3e7f 100644 --- a/src/position.cpp +++ b/src/position.cpp @@ -1105,6 +1105,8 @@ bool Position::see_ge(Move m, int threshold) const { Square from = m.from_sq(), to = m.to_sq(); + assert(piece_on(from) != NO_PIECE); + int swap = PieceValue[piece_on(to)] - threshold; if (swap < 0) return false; From e18ed795f2603d6482ac18bc0a6546e2a18406ae Mon Sep 17 00:00:00 2001 From: Daniel Samek Date: Sun, 5 Oct 2025 10:38:21 +0200 Subject: [PATCH 102/107] Introduce 4-ply continuation correction history Passed STC: LLR: 2.94 (-2.94,2.94) <0.00,2.00> Total: 113984 W: 29752 L: 29323 D: 54909 Ptnml(0-2): 376, 13191, 29435, 13608, 382 https://tests.stockfishchess.org/tests/view/68dc3576fa806e2e8393bd93 Passed LTC: LLR: 2.94 (-2.94,2.94) <0.50,2.50> Total: 80154 W: 20823 L: 20417 D: 38914 Ptnml(0-2): 47, 8600, 22383, 8994, 53 https://tests.stockfishchess.org/tests/view/68df83e0fa806e2e8393cbe8 Passed non-regression VLTC (rebased): LLR: 2.98 (-2.94,2.94) <-1.75,0.25> Total: 38158 W: 9992 L: 9805 D: 18361 Ptnml(0-2): 3, 3406, 12075, 3591, 4 https://tests.stockfishchess.org/tests/view/68e22f2afa806e2e8393d0ed closes https://github.com/official-stockfish/Stockfish/pull/6345 bench 2169281 --- src/search.cpp | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/search.cpp b/src/search.cpp index 6b2c28da2..8dcdd5ed7 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -84,6 +84,7 @@ int correction_value(const Worker& w, const Position& pos, const Stack* const ss const auto bnpcv = w.nonPawnCorrectionHistory[non_pawn_index(pos)][BLACK][us]; const auto cntcv = m.is_ok() ? (*(ss - 2)->continuationCorrectionHistory)[pos.piece_on(m.to_sq())][m.to_sq()] + + (*(ss - 4)->continuationCorrectionHistory)[pos.piece_on(m.to_sq())][m.to_sq()] : 8; return 9536 * pcv + 8494 * micv + 10132 * (wnpcv + bnpcv) + 7156 * cntcv; @@ -112,8 +113,12 @@ void update_correction_history(const Position& pos, << bonus * nonPawnWeight / 128; if (m.is_ok()) - (*(ss - 2)->continuationCorrectionHistory)[pos.piece_on(m.to_sq())][m.to_sq()] - << bonus * 137 / 128; + { + const Square to = m.to_sq(); + const Piece pc = pos.piece_on(m.to_sq()); + (*(ss - 2)->continuationCorrectionHistory)[pc][to] << bonus * 137 / 128; + (*(ss - 4)->continuationCorrectionHistory)[pc][to] << bonus * 64 / 128; + } } // Add a small random component to draw evaluations to avoid 3-fold blindness From fc5d296f9dfa62444dde910985c98e9055c1d9a3 Mon Sep 17 00:00:00 2001 From: dav1312 <63931154+dav1312@users.noreply.github.com> Date: Tue, 7 Oct 2025 13:29:52 +0200 Subject: [PATCH 103/107] Update get_native_properties.sh for AVXVNNI Update get_native_properties.sh to detect and report 'x86-64-avxvnni' when the CPU supports it. closes https://github.com/official-stockfish/Stockfish/pull/6346 No functional change --- scripts/get_native_properties.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/scripts/get_native_properties.sh b/scripts/get_native_properties.sh index dec5998da..67dd60ca5 100755 --- a/scripts/get_native_properties.sh +++ b/scripts/get_native_properties.sh @@ -45,6 +45,8 @@ set_arch_x86_64() { true_arch='x86-64-vnni512' elif check_flags 'avx512f' 'avx512bw'; then true_arch='x86-64-avx512' + elif check_flags 'avxvnni'; then + true_arch='x86-64-avxvnni' elif [ -z "${znver_1_2+1}" ] && check_flags 'bmi2'; then true_arch='x86-64-bmi2' elif check_flags 'avx2'; then From c956df4cbb4ffded736a95baa1bde7df6d48e319 Mon Sep 17 00:00:00 2001 From: mstembera Date: Tue, 7 Oct 2025 12:38:39 -0700 Subject: [PATCH 104/107] Split accumulator 3-way for avxvnni This does the same thing for x86-64-avxvnni as #6336, #6339. closes https://github.com/official-stockfish/Stockfish/pull/6347 No functional change --- .../layers/affine_transform_sparse_input.h | 65 ++++++++++--------- 1 file changed, 36 insertions(+), 29 deletions(-) diff --git a/src/nnue/layers/affine_transform_sparse_input.h b/src/nnue/layers/affine_transform_sparse_input.h index effda826b..472da834f 100644 --- a/src/nnue/layers/affine_transform_sparse_input.h +++ b/src/nnue/layers/affine_transform_sparse_input.h @@ -254,6 +254,7 @@ class AffineTransformSparseInput { #elif defined(USE_AVX2) using invec_t = __m256i; using outvec_t = __m256i; + #define vec_add_32 _mm256_add_epi32 #define vec_set_32 _mm256_set1_epi32 #define vec_add_dpbusd_32 SIMD::m256_add_dpbusd_epi32 #elif defined(USE_SSSE3) @@ -272,21 +273,19 @@ class AffineTransformSparseInput { #define vec_set_32(a) vreinterpretq_s8_u32(vdupq_n_u32(a)) #define vec_add_dpbusd_32 SIMD::neon_m128_add_dpbusd_epi32 #endif - static constexpr IndexType OutputSimdWidth = sizeof(outvec_t) / sizeof(OutputType); - + constexpr IndexType OutputSimdWidth = sizeof(outvec_t) / sizeof(OutputType); constexpr IndexType NumChunks = ceil_to_multiple(InputDimensions, 8) / ChunkSize; constexpr IndexType NumAccums = OutputDimensions / OutputSimdWidth; - // If there's only one accumulator and we're using high-latency dot product instructions, - // split it to create three separate dependency chains and merge at the end - constexpr bool SplitAccums = + // If we're using high-latency dot product instructions, split the accumulators + // to create 3 separate dependency chains and merge at the end + constexpr IndexType NumRegs = #if defined(USE_VNNI) - NumAccums == 1; + 3 * NumAccums; #else - false; + NumAccums; #endif - constexpr IndexType NumRegs = SplitAccums ? 3 * NumAccums : NumAccums; - std::uint16_t nnz[NumChunks]; - IndexType count; + std::uint16_t nnz[NumChunks]; + IndexType count; const auto input32 = reinterpret_cast(input); @@ -303,30 +302,34 @@ class AffineTransformSparseInput { // convince GCC to not do weird pointer arithmetic in the following loop const std::int8_t* weights_cp = weights; + #if defined(USE_VNNI) + for (IndexType k = NumAccums; k < NumRegs; ++k) + acc[k] = vec_zero(); - if constexpr (SplitAccums) + while (start < end - 2) { - acc[1] = acc[2] = vec_set_32(0); - while (start < end - 2) + const std::ptrdiff_t i0 = *start++; + const std::ptrdiff_t i1 = *start++; + const std::ptrdiff_t i2 = *start++; + const invec_t in0 = vec_set_32(input32[i0]); + const invec_t in1 = vec_set_32(input32[i1]); + const invec_t in2 = vec_set_32(input32[i2]); + const auto col0 = + reinterpret_cast(&weights_cp[i0 * OutputDimensions * ChunkSize]); + const auto col1 = + reinterpret_cast(&weights_cp[i1 * OutputDimensions * ChunkSize]); + const auto col2 = + reinterpret_cast(&weights_cp[i2 * OutputDimensions * ChunkSize]); + for (IndexType k = 0; k < NumAccums; ++k) { - const std::ptrdiff_t i0 = *start++; - const std::ptrdiff_t i1 = *start++; - const std::ptrdiff_t i2 = *start++; - const invec_t in0 = vec_set_32(input32[i0]); - const invec_t in1 = vec_set_32(input32[i1]); - const invec_t in2 = vec_set_32(input32[i2]); - const auto col0 = - reinterpret_cast(&weights_cp[i0 * OutputDimensions * ChunkSize]); - const auto col1 = - reinterpret_cast(&weights_cp[i1 * OutputDimensions * ChunkSize]); - const auto col2 = - reinterpret_cast(&weights_cp[i2 * OutputDimensions * ChunkSize]); - vec_add_dpbusd_32(acc[0], in0, *col0); - vec_add_dpbusd_32(acc[1], in1, *col1); - vec_add_dpbusd_32(acc[2], in2, *col2); + vec_add_dpbusd_32(acc[k], in0, col0[k]); + vec_add_dpbusd_32(acc[k + NumAccums], in1, col1[k]); + vec_add_dpbusd_32(acc[k + 2 * NumAccums], in2, col2[k]); } - acc[0] = vec_add_32(vec_add_32(acc[0], acc[1]), acc[2]); } + for (IndexType k = 0; k < NumAccums; ++k) + acc[k] = vec_add_32(vec_add_32(acc[k], acc[k + NumAccums]), acc[k + 2 * NumAccums]); + #endif while (start < end) { const std::ptrdiff_t i = *start++; @@ -340,8 +343,12 @@ class AffineTransformSparseInput { outvec_t* outptr = reinterpret_cast(output); for (IndexType k = 0; k < NumAccums; ++k) outptr[k] = acc[k]; + #undef vec_set_32 #undef vec_add_dpbusd_32 + #ifdef vec_add_32 + #undef vec_add_32 + #endif #else // Use dense implementation for the other architectures. affine_transform_non_ssse3( From 63d449d1d9b8fe5c01e35c7cf874371a1c82ccb2 Mon Sep 17 00:00:00 2001 From: rustam-cpp Date: Wed, 8 Oct 2025 22:50:28 +0300 Subject: [PATCH 105/107] bigger PAWN_HISTORY_SIZE STC (10+0.1 th1) was accepted: LLR: 2.95 (-2.94,2.94) <0.00,2.00> Total: 75712 W: 19701 L: 19326 D: 36685 Ptnml(0-2): 254, 8738, 19513, 9081, 270 https://tests.stockfishchess.org/tests/view/68e286d5fa806e2e8393d160 LTC (60+0.6 th1) was accepted: LLR: 2.96 (-2.94,2.94) <0.50,2.50> Total: 108492 W: 28068 L: 27604 D: 52820 Ptnml(0-2): 60, 11639, 30390, 12091, 66 https://tests.stockfishchess.org/tests/view/68e3e564a017f472e763dac0 closes https://github.com/official-stockfish/Stockfish/pull/6350 bench 2128316 --- AUTHORS | 1 + src/history.h | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/AUTHORS b/AUTHORS index 0429f9f0a..8d57062cc 100644 --- a/AUTHORS +++ b/AUTHORS @@ -217,6 +217,7 @@ Ronald de Man (syzygy1, syzygy) Ron Britvich (Britvich) rqs Rui Coelho (ruicoelhopedro) +rustam-cpp Ryan Schmitt Ryan Takker Sami Kiminki (skiminki) diff --git a/src/history.h b/src/history.h index 1f7abc542..940e98991 100644 --- a/src/history.h +++ b/src/history.h @@ -33,7 +33,7 @@ namespace Stockfish { -constexpr int PAWN_HISTORY_SIZE = 1024; // has to be a power of 2 +constexpr int PAWN_HISTORY_SIZE = 8192; // has to be a power of 2 constexpr int CORRECTION_HISTORY_SIZE = 32768; // has to be a power of 2 constexpr int CORRECTION_HISTORY_LIMIT = 1024; constexpr int LOW_PLY_HISTORY_SIZE = 5; From e7a4708ad558da49f88c8c72aed8c9290fef8d05 Mon Sep 17 00:00:00 2001 From: Daniel Monroe Date: Tue, 7 Oct 2025 18:25:08 -0400 Subject: [PATCH 106/107] Remove condition in qsearch Instead of skipping non-captures when pawn history is exceptionally high, skip all non-captures Passed non-regression STC LLR: 2.96 (-2.94,2.94) <-1.75,0.25> Total: 38016 W: 10018 L: 9795 D: 18203 Ptnml(0-2): 155, 4346, 9755, 4625, 127 https://tests.stockfishchess.org/tests/view/68e43d4aa017f472e763db2e Passed rebased non-regression LTC LLR: 2.94 (-2.94,2.94) <-1.75,0.25> Total: 96048 W: 24854 L: 24710 D: 46484 Ptnml(0-2): 47, 10504, 26780, 10644, 49 https://tests.stockfishchess.org/tests/view/68e59352a017f472e763dcf9 closes https://github.com/official-stockfish/Stockfish/pull/6355 bench 2343840 --- AUTHORS | 2 +- src/search.cpp | 5 ++--- 2 files changed, 3 insertions(+), 4 deletions(-) diff --git a/AUTHORS b/AUTHORS index 8d57062cc..4729afeab 100644 --- a/AUTHORS +++ b/AUTHORS @@ -62,7 +62,7 @@ CSTENTOR Dale Weiler (graphitemaster) Daniel Axtens (daxtens) Daniel Dugovic (ddugovic) -Daniel Monroe (Ergodice) +Daniel Monroe (daniel-monroe) Daniel Samek (DanSamek) Dan Schmidt (dfannius) Dariusz Orzechowski (dorzechowski) diff --git a/src/search.cpp b/src/search.cpp index 8dcdd5ed7..fa2355130 100644 --- a/src/search.cpp +++ b/src/search.cpp @@ -1634,9 +1634,8 @@ Value Search::Worker::qsearch(Position& pos, Stack* ss, Value alpha, Value beta) } } - // Continuation history based pruning - if (!capture - && pawnHistory[pawn_history_index(pos)][pos.moved_piece(move)][move.to_sq()] < 7300) + // Skip non-captures + if (!capture) continue; // Do not search moves with bad enough SEE values From 315f8ba4bf7d846b35f984d5e6040c14a512d9b9 Mon Sep 17 00:00:00 2001 From: "Robert Nurnberg @ elitebook" Date: Tue, 14 Oct 2025 08:40:27 +0200 Subject: [PATCH 107/107] let CI check for mate scores outside the valid range closes https://github.com/official-stockfish/Stockfish/pull/6358 No functional change --- .github/workflows/matetrack.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/matetrack.yml b/.github/workflows/matetrack.yml index c4d14fc7b..43d35ca18 100644 --- a/.github/workflows/matetrack.yml +++ b/.github/workflows/matetrack.yml @@ -24,7 +24,7 @@ jobs: with: repository: vondele/matetrack path: matetrack - ref: 4f8a80860ed8f3607f05a9195df8b40203bdc360 + ref: 2d96fa3373f90edb032b7ea7468473fb9e6f0343 persist-credentials: false - name: matetrack install deps