Skip to content

Commit fc74309

Browse files
VizvezdenecJoachim26
authored andcommitted
Big search tuning
Most credits for this patch should go to @candirufish. Based on his big search tuning (1M games at 20+0.1s) https://tests.stockfishchess.org/tests/view/61fc7a6ed508ec6a1c9f4b7d with some hand polishing on top of it, which includes : a) correcting trend sigmoid - for some reason original tuning resulted in it being negative. This heuristic was proven to be worth some elo for years so reversing it sign is probably some random artefact; b) remove changes to continuation history based pruning - this heuristic historically was really good at providing green STCs and then failing at LTC miserably if we tried to make it more strict, original tuning was done at short time control and thus it became more strict - which doesn't scale to longer time controls; c) remove changes to improvement - not really indended :). passed STC https://tests.stockfishchess.org/tests/view/6203526e88ae2c84271c2ee2 LLR: 2.94 (-2.94,2.94) <0.00,2.50> Total: 16840 W: 4604 L: 4363 D: 7873 Ptnml(0-2): 82, 1780, 4449, 2033, 76 passed LTC https://tests.stockfishchess.org/tests/view/620376e888ae2c84271c35d4 LLR: 2.96 (-2.94,2.94) <0.50,3.00> Total: 17232 W: 4771 L: 4542 D: 7919 Ptnml(0-2): 14, 1655, 5048, 1886, 13 closes official-stockfish#3926 bench 5030992
1 parent 56d18c4 commit fc74309

File tree

1 file changed

+49
-49
lines changed

1 file changed

+49
-49
lines changed

src/search.cpp

Lines changed: 49 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -65,18 +65,19 @@ namespace {
6565

6666
// Futility margin
6767
Value futility_margin(Depth d, bool improving) {
68-
return Value(214 * (d - improving));
68+
return Value(171 * (d - improving));
6969
}
7070

7171
// Reductions lookup table, initialized at startup
7272
int Reductions[MAX_MOVES]; // [depth or moveNumber]
7373

7474
Depth reduction(bool i, Depth d, int mn, Value delta, Value rootDelta) {
7575
int r = Reductions[d] * Reductions[mn];
76+
7677
if (rootDelta != 0)
77-
return (r + 1358 - int(delta) * 1024 / int(rootDelta)) / 1024 + (!i && r > 904);
78-
else // avoid divide by zero error
79-
return (r + 1358 - int(delta) * 1024) / 1024 + (!i && r > 904);
78+
return (r + 1575 - int(delta) * 1024 / int(rootDelta)) / 1024 + (!i && r > 1011);
79+
else // SFplus: avoid divide by zero error
80+
return (r + 1575 - int(delta) * 1024) / 1024 + (!i && r > 1011);
8081
}
8182

8283
constexpr int futility_move_count(bool improving, Depth depth) {
@@ -85,7 +86,7 @@ namespace {
8586

8687
// History and stats update bonus, based on depth
8788
int stat_bonus(Depth d) {
88-
return std::min((6 * d + 229) * d - 215 , 2000);
89+
return std::min((7 * d + 254) * d - 206 , 1990);
8990
}
9091

9192
// Add a small random component to draw evaluations to avoid 3-fold blindness
@@ -162,7 +163,7 @@ namespace {
162163
void Search::init() {
163164

164165
for (int i = 1; i < MAX_MOVES; ++i)
165-
Reductions[i] = int((21.9 + std::log(Threads.size()) / 2) * std::log(i));
166+
Reductions[i] = int((21.5 + std::log(Threads.size()) / 2) * std::log(i));
166167
}
167168

168169

@@ -345,10 +346,10 @@ void Thread::search() {
345346

346347
multiPV = std::min(multiPV, rootMoves.size());
347348

348-
complexityAverage.set(232, 1);
349+
complexityAverage.set(190, 1);
349350

350351
trend = SCORE_ZERO;
351-
optimism[ us] = Value(25);
352+
optimism[ us] = Value(34);
352353
optimism[~us] = -optimism[us];
353354

354355
int searchAgainCounter = 0;
@@ -418,16 +419,16 @@ void Thread::search() {
418419
if (rootDepth >= 4)
419420
{
420421
Value prev = rootMoves[pvIdx].averageScore;
421-
delta = Value(17) + int(prev) * prev / 16384;
422+
delta = Value(16) + int(prev) * prev / 16384;
422423
alpha = std::max(prev - delta,-VALUE_INFINITE);
423424
beta = std::min(prev + delta, VALUE_INFINITE);
424425

425426
// Adjust trend and optimism based on root move's previousScore
426-
int tr = sigmoid(prev, 0, 0, 147, 113, 1);
427+
int tr = sigmoid(prev, 6, 13, 96, 110, 1);
427428
trend = (us == WHITE ? make_score(tr, tr / 2)
428429
: -make_score(tr, tr / 2));
429430

430-
int opt = sigmoid(prev, 0, 25, 147, 14464, 256);
431+
int opt = sigmoid(prev, 7, 21, 94, 14786, 221);
431432
optimism[ us] = Value(opt);
432433
optimism[~us] = -optimism[us];
433434
}
@@ -482,7 +483,7 @@ void Thread::search() {
482483
else
483484
break;
484485

485-
delta += delta / 4 + 5;
486+
delta += delta / 4 + 3;
486487

487488
assert(alpha >= -VALUE_INFINITE && beta <= VALUE_INFINITE);
488489
}
@@ -528,17 +529,17 @@ void Thread::search() {
528529
&& !Threads.stop
529530
&& !mainThread->stopOnPonderhit)
530531
{
531-
double fallingEval = (142 + 12 * (mainThread->bestPreviousAverageScore - bestValue)
532-
+ 6 * (mainThread->iterValue[iterIdx] - bestValue)) / 825.0;
532+
double fallingEval = (87 + 12 * (mainThread->bestPreviousAverageScore - bestValue)
533+
+ 6 * (mainThread->iterValue[iterIdx] - bestValue)) / 777.20;
533534
fallingEval = std::clamp(fallingEval, 0.5, 1.5);
534535

535536
// If the bestMove is stable over several iterations, reduce time accordingly
536-
timeReduction = lastBestMoveDepth + 9 < completedDepth ? 1.92 : 0.95;
537-
double reduction = (1.47 + mainThread->previousTimeReduction) / (2.32 * timeReduction);
537+
timeReduction = lastBestMoveDepth + 8 < completedDepth ? 1.70 : 0.91;
538+
double reduction = (1.59 + mainThread->previousTimeReduction) / (2.33 * timeReduction);
538539
double bestMoveInstability = 1.073 + std::max(1.0, 2.25 - 9.9 / rootDepth)
539540
* totBestMoveChanges / Threads.size();
540541
int complexity = mainThread->complexityAverage.value();
541-
double complexPosition = std::clamp(1.0 + (complexity - 232) / 1750.0, 0.5, 1.5);
542+
double complexPosition = std::clamp(1.0 + (complexity - 312) / 1750.0, 0.5, 1.5);
542543

543544
double totalTime = Time.optimum() * fallingEval * reduction * bestMoveInstability * complexPosition;
544545

@@ -559,7 +560,7 @@ void Thread::search() {
559560
}
560561
else if ( Threads.increaseDepth
561562
&& !mainThread->ponder
562-
&& Time.elapsed() > totalTime * 0.58)
563+
&& Time.elapsed() > totalTime * 0.55)
563564
Threads.increaseDepth = false;
564565
else
565566
Threads.increaseDepth = true;
@@ -857,19 +858,19 @@ namespace {
857858
// Step 8. Futility pruning: child node (~25 Elo).
858859
// The depth condition is important for mate finding.
859860
if ( !ss->ttPv
860-
&& depth < 9
861+
&& depth < 8
861862
&& eval - futility_margin(depth, improving) - (ss-1)->statScore / 256 >= beta
862863
&& eval >= beta
863-
&& eval < 15000) // 50% larger than VALUE_KNOWN_WIN, but smaller than TB wins.
864+
&& eval < 17548) // 50% larger than VALUE_KNOWN_WIN, but smaller than TB wins.
864865
return eval;
865866

866867
// Step 9. Null move search with verification search (~22 Elo)
867868
if ( !PvNode
868869
&& (ss-1)->currentMove != MOVE_NULL
869-
&& (ss-1)->statScore < 23767
870+
&& (ss-1)->statScore < 13706
870871
&& eval >= beta
871872
&& eval >= ss->staticEval
872-
&& ss->staticEval >= beta - 20 * depth - improvement / 15 + 204 + complexity / 25
873+
&& ss->staticEval >= beta - 19 * depth - improvement / 15 + 200 + complexity / 25
873874
&& !excludedMove
874875
&& pos.non_pawn_material(us)
875876
&& (ss->ply >= thisThread->nmpMinPly || us != thisThread->nmpColor))
@@ -913,13 +914,13 @@ namespace {
913914
}
914915
}
915916

916-
probCutBeta = beta + 209 - 44 * improving;
917+
probCutBeta = beta + 229 - 47 * improving;
917918

918919
// Step 10. ProbCut (~4 Elo)
919920
// If we have a good enough capture and a reduced search returns a value
920921
// much above beta, we can (almost) safely prune the previous move.
921922
if ( !PvNode
922-
&& depth > 4
923+
&& depth > 3
923924
&& abs(beta) < VALUE_TB_WIN_IN_MAX_PLY
924925
// if value from transposition table is lower than probCutBeta, don't attempt probCut
925926
// there and in further interactions with transposition table cutoff depth is set to depth - 3
@@ -940,7 +941,6 @@ namespace {
940941
if (move != excludedMove && pos.legal(move))
941942
{
942943
assert(pos.capture_or_promotion(move));
943-
assert(depth >= 5);
944944

945945
captureOrPromotion = true;
946946

@@ -978,19 +978,19 @@ namespace {
978978

979979
// Step 11. If the position is not in TT, decrease depth by 2 or 1 depending on node type (~3 Elo)
980980
if ( PvNode
981-
&& depth >= 6
981+
&& depth >= 4
982982
&& !ttMove)
983983
depth -= 2;
984984

985985
if ( cutNode
986-
&& depth >= 9
986+
&& depth >= 7
987987
&& !ttMove)
988988
depth--;
989989

990990
moves_loop: // When in check, search starts here
991991

992992
// Step 12. A small Probcut idea, when we are in check (~0 Elo)
993-
probCutBeta = beta + 409;
993+
probCutBeta = beta + 401;
994994
if ( ss->inCheck
995995
&& !PvNode
996996
&& depth >= 4
@@ -1086,12 +1086,12 @@ namespace {
10861086
&& !PvNode
10871087
&& lmrDepth < 6
10881088
&& !ss->inCheck
1089-
&& ss->staticEval + 342 + 238 * lmrDepth + PieceValue[EG][pos.piece_on(to_sq(move))]
1089+
&& ss->staticEval + 392 + 207 * lmrDepth + PieceValue[EG][pos.piece_on(to_sq(move))]
10901090
+ captureHistory[movedPiece][to_sq(move)][type_of(pos.piece_on(to_sq(move)))] / 8 < alpha)
10911091
continue;
10921092

10931093
// SEE based pruning (~9 Elo)
1094-
if (!pos.see_ge(move, Value(-217) * depth))
1094+
if (!pos.see_ge(move, Value(-200) * depth))
10951095
continue;
10961096
}
10971097
else
@@ -1109,12 +1109,12 @@ namespace {
11091109

11101110
// Futility pruning: parent node (~9 Elo)
11111111
if ( !ss->inCheck
1112-
&& lmrDepth < 8
1113-
&& ss->staticEval + 138 + 137 * lmrDepth + history / 64 <= alpha)
1112+
&& lmrDepth < 11
1113+
&& ss->staticEval + 131 + 137 * lmrDepth + history / 64 <= alpha)
11141114
continue;
11151115

11161116
// Prune moves with negative SEE (~3 Elo)
1117-
if (!pos.see_ge(move, Value(-21 * lmrDepth * lmrDepth - 21 * lmrDepth)))
1117+
if (!pos.see_ge(move, Value(-25 * lmrDepth * lmrDepth - 29 * lmrDepth)))
11181118
continue;
11191119
}
11201120
}
@@ -1150,7 +1150,7 @@ namespace {
11501150

11511151
// Avoid search explosion by limiting the number of double extensions
11521152
if ( !PvNode
1153-
&& value < singularBeta - 75
1153+
&& value < singularBeta - 71
11541154
&& ss->doubleExtensions <= 6)
11551155
extension = 2;
11561156
}
@@ -1170,15 +1170,15 @@ namespace {
11701170

11711171
// Check extensions (~1 Elo)
11721172
else if ( givesCheck
1173-
&& depth > 6
1174-
&& abs(ss->staticEval) > 100)
1173+
&& depth > 7
1174+
&& abs(ss->staticEval) > 128)
11751175
extension = 1;
11761176

11771177
// Quiet ttMove extensions (~0 Elo)
11781178
else if ( PvNode
11791179
&& move == ttMove
11801180
&& move == ss->killers[0]
1181-
&& (*contHist[0])[movedPiece][to_sq(move)] >= 10000)
1181+
&& (*contHist[0])[movedPiece][to_sq(move)] >= 8932)
11821182
extension = 1;
11831183
}
11841184

@@ -1205,8 +1205,8 @@ namespace {
12051205
// We use various heuristics for the sons of a node after the first son has
12061206
// been searched. In general we would like to reduce them, but there are many
12071207
// cases where we extend a son if it has good chances to be "interesting".
1208-
if ( depth >= 3
1209-
&& moveCount > 1 + 2 * rootNode
1208+
if ( depth >= 2
1209+
&& moveCount > 1 + rootNode
12101210
&& ( !ss->ttPv
12111211
|| !captureOrPromotion
12121212
|| (cutNode && (ss-1)->moveCount > 1)))
@@ -1215,7 +1215,7 @@ namespace {
12151215

12161216
// Decrease reduction at some PvNodes (~2 Elo)
12171217
if ( PvNode
1218-
&& bestMoveCount <= 3)
1218+
&& bestMoveCount <= 4)
12191219
r--;
12201220

12211221
// Decrease reduction if position is or has been on the PV
@@ -1225,7 +1225,7 @@ namespace {
12251225
r -= 2;
12261226

12271227
// Decrease reduction if opponent's move count is high (~1 Elo)
1228-
if ((ss-1)->moveCount > 13)
1228+
if ((ss-1)->moveCount > 7)
12291229
r--;
12301230

12311231
// Increase reduction for cut nodes (~3 Elo)
@@ -1240,18 +1240,18 @@ namespace {
12401240
+ (*contHist[0])[movedPiece][to_sq(move)]
12411241
+ (*contHist[1])[movedPiece][to_sq(move)]
12421242
+ (*contHist[3])[movedPiece][to_sq(move)]
1243-
- 4923;
1243+
- 4142;
12441244

12451245
// Decrease/increase reduction for moves with a good/bad history (~30 Elo)
1246-
r -= ss->statScore / 14721;
1246+
r -= ss->statScore / 15328;
12471247

12481248
// In general we want to cap the LMR depth search at newDepth. But if reductions
12491249
// are really negative and movecount is low, we allow this move to be searched
12501250
// deeper than the first move (this may lead to hidden double extensions).
12511251
int deeper = r >= -1 ? 0
12521252
: moveCount <= 5 ? 2
1253-
: PvNode && depth > 6 ? 1
1254-
: cutNode && moveCount <= 7 ? 1
1253+
: PvNode && depth > 4 ? 1
1254+
: cutNode && moveCount <= 5 ? 1
12551255
: 0;
12561256

12571257
Depth d = std::clamp(newDepth - r, 1, newDepth + deeper);
@@ -1260,7 +1260,7 @@ namespace {
12601260

12611261
// If the son is reduced and fails high it will be re-searched at full depth
12621262
doFullDepthSearch = value > alpha && d < newDepth;
1263-
doDeeperSearch = value > (alpha + 62 + 20 * (newDepth - d));
1263+
doDeeperSearch = value > (alpha + 80 + 20 * (newDepth - d));
12641264
didLMR = true;
12651265
}
12661266
else
@@ -1281,7 +1281,7 @@ namespace {
12811281
: -stat_bonus(newDepth);
12821282

12831283
if (captureOrPromotion)
1284-
bonus /= 4;
1284+
bonus /= 5;
12851285

12861286
update_continuation_histories(ss, movedPiece, to_sq(move), bonus);
12871287
}
@@ -1412,7 +1412,7 @@ namespace {
14121412
//or fail low was really bad
14131413
bool extraBonus = PvNode
14141414
|| cutNode
1415-
|| bestValue < alpha - 94 * depth;
1415+
|| bestValue < alpha - 99 * depth;
14161416

14171417
update_continuation_histories(ss-1, pos.piece_on(prevSq), prevSq, stat_bonus(depth) * (1 + extraBonus));
14181418
}
@@ -1543,7 +1543,7 @@ namespace {
15431543
if (PvNode && bestValue > alpha)
15441544
alpha = bestValue;
15451545

1546-
futilityBase = bestValue + 155;
1546+
futilityBase = bestValue + 127;
15471547
}
15481548

15491549
const PieceToHistory* contHist[] = { (ss-1)->continuationHistory, (ss-2)->continuationHistory,

0 commit comments

Comments
 (0)