From 787b2e1bfa5a363860f1a4ed52c67910188ec681 Mon Sep 17 00:00:00 2001 From: Jay Honnold Date: Fri, 29 Mar 2024 17:26:21 -0700 Subject: [PATCH] SPSA Tune for 7016 iterations (#554) Bench: 3040242 Elo | 5.07 +- 4.13 (95%) SPRT | 60.0+0.60s Threads=1 Hash=64MB LLR | 2.36 (-2.25, 2.89) [0.00, 2.50] Games | N: 12480 W: 2965 L: 2783 D: 6732 Penta | [21, 1309, 3394, 1499, 17] http://chess.grantnet.us/test/36083/ --- src/history.c | 2 +- src/history.h | 2 +- src/makefile | 2 +- src/search.c | 50 +++++++++++++++++++++++++------------------------- src/uci.c | 4 ++-- 5 files changed, 30 insertions(+), 30 deletions(-) diff --git a/src/history.c b/src/history.c index 291caf61..00f1bb00 100644 --- a/src/history.c +++ b/src/history.c @@ -47,7 +47,7 @@ void UpdateHistories(SearchStack* ss, // Only increase the best move history when it // wasn't trivial. This idea was first thought of // by Alayan in Ethereal - if (nQ > 1 || depth > 3) { + if (nQ > 1 || depth > 4) { AddHistoryHeuristic(&HH(stm, bestMove, board->threatened), inc); UpdateCH(ss, bestMove, inc); } diff --git a/src/history.h b/src/history.h index a874f4b8..8e44cabe 100644 --- a/src/history.h +++ b/src/history.h @@ -58,7 +58,7 @@ INLINE void AddCounterMove(ThreadData* thread, Move move, Move parent) { } INLINE int16_t HistoryBonus(int depth) { - return Min(1896, 4 * depth * depth + 120 * depth - 120); + return Min(1729, 4 * depth * depth + 164 * depth - 113); } INLINE void AddHistoryHeuristic(int16_t* entry, int16_t inc) { diff --git a/src/makefile b/src/makefile index cd53c4c2..cf827e9c 100644 --- a/src/makefile +++ b/src/makefile @@ -3,7 +3,7 @@ EXE = berserk SRC = attacks.c bench.c berserk.c bits.c board.c eval.c history.c move.c movegen.c movepick.c perft.c random.c \ search.c see.c tb.c thread.c transposition.c uci.c util.c zobrist.c nn/accumulator.c nn/evaluate.c pyrrhic/tbprobe.c CC = clang -VERSION = 20240324 +VERSION = 20240329 MAIN_NETWORK = berserk-d43206fe90e4.nn EVALFILE = $(MAIN_NETWORK) DEFS = -DVERSION=\"$(VERSION)\" -DEVALFILE=\"$(EVALFILE)\" -DNDEBUG diff --git a/src/search.c b/src/search.c index f1894531..a9bc36d0 100644 --- a/src/search.c +++ b/src/search.c @@ -49,7 +49,7 @@ int STATIC_PRUNE[2][MAX_SEARCH_PLY]; void InitPruningAndReductionTables() { for (int depth = 1; depth < MAX_SEARCH_PLY; depth++) for (int moves = 1; moves < 64; moves++) - LMR[depth][moves] = log(depth) * log(moves) / 2.1872 + 0.2487; + LMR[depth][moves] = log(depth) * log(moves) / 2.0385 + 0.2429; LMR[0][0] = LMR[0][1] = LMR[1][0] = 0; @@ -57,11 +57,11 @@ void InitPruningAndReductionTables() { // LMP has both a improving (more strict) and non-improving evalution // parameter for lmp. If the evaluation is getting better we want to check // more - LMP[0][depth] = 1.2973 + 0.3772 * depth * depth; - LMP[1][depth] = 2.7002 + 0.9448 * depth * depth; + LMP[0][depth] = 1.3050 + 0.3503 * depth * depth; + LMP[1][depth] = 2.1885 + 0.9911 * depth * depth; - STATIC_PRUNE[0][depth] = -14.9419 * depth * depth; // quiet move cutoff - STATIC_PRUNE[1][depth] = -103.9379 * depth; // capture cutoff + STATIC_PRUNE[0][depth] = -15.2703 * depth * depth; // quiet move cutoff + STATIC_PRUNE[1][depth] = -94.0617 * depth; // capture cutoff } } @@ -299,7 +299,7 @@ void Search(ThreadData* thread) { break; // delta x 1.25 - delta += delta / 4; + delta += 17 * delta / 64; } SortRootMoves(thread, 0); @@ -326,7 +326,7 @@ void Search(ThreadData* thread) { if (Limits.timeset && thread->depth >= 5 && !Threads.stopOnPonderHit) { int sameBestMove = bestMove == previousBestMove; // same move? searchStability = sameBestMove ? Min(10, searchStability + 1) : 0; // increase how stable our best move is - double stabilityFactor = 1.3658 - 0.0482 * searchStability; + double stabilityFactor = 1.3110 - 0.0533 * searchStability; Score searchScoreDiff = scores[thread->depth - 3] - bestScore; Score prevScoreDiff = thread->previousScore - bestScore; @@ -335,14 +335,14 @@ void Search(ThreadData* thread) { if (thread->previousScore == UNKNOWN) searchScoreDiff *= 2, prevScoreDiff = 0; - double scoreChangeFactor = 0.0995 + // - 0.0286 * searchScoreDiff * (searchScoreDiff > 0) + // + double scoreChangeFactor = 0.1127 + // + 0.0262 * searchScoreDiff * (searchScoreDiff > 0) + // 0.0261 * prevScoreDiff * (prevScoreDiff > 0); - scoreChangeFactor = Max(0.4843, Min(1.4498, scoreChangeFactor)); + scoreChangeFactor = Max(0.5028, Min(1.6561, scoreChangeFactor)); uint64_t bestMoveNodes = thread->rootMoves[0].nodes; double pctNodesNotBest = 1.0 - (double) bestMoveNodes / thread->nodes; - double nodeCountFactor = Max(0.5464, pctNodesNotBest * 2.1394 + 0.4393); + double nodeCountFactor = Max(0.5630, pctNodesNotBest * 2.2669 + 0.4499); if (bestScore >= TB_WIN_BOUND) nodeCountFactor = 0.5; @@ -514,13 +514,13 @@ int Negamax(int alpha, int beta, int depth, int cutnode, ThreadData* thread, PV* // Reverse Futility Pruning // i.e. the static eval is so far above beta we prune - if (depth <= 8 && !ss->skip && eval < TB_WIN_BOUND && eval >= beta && - eval - 67 * depth + 112 * (improving && !opponentHasEasyCapture) >= beta && - (!hashMove || GetHistory(ss, thread, hashMove) > 12525)) + if (depth <= 9 && !ss->skip && eval < TB_WIN_BOUND && eval >= beta && + eval - 70 * depth + 118 * (improving && !opponentHasEasyCapture) >= beta && + (!hashMove || GetHistory(ss, thread, hashMove) > 11800)) return (eval + beta) / 2; // Razoring - if (depth <= 6 && eval + 252 * depth <= alpha) { + if (depth <= 5 && eval + 214 * depth <= alpha) { score = Quiesce(alpha, beta, 0, thread, ss); if (score <= alpha) return score; @@ -532,7 +532,7 @@ int Negamax(int alpha, int beta, int depth, int cutnode, ThreadData* thread, PV* // threats) if (depth >= 4 && (ss - 1)->move != NULL_MOVE && !ss->skip && !opponentHasEasyCapture && eval >= beta && HasNonPawn(board, board->stm) && (ss->ply >= thread->nmpMinPly || board->stm != thread->npmColor)) { - int R = 4 + 342 * depth / 1024 + Min(10 * (eval - beta) / 1024, 4); + int R = 4 + 385 * depth / 1024 + Min(10 * (eval - beta) / 1024, 4); TTPrefetch(KeyAfter(board, NULL_MOVE)); ss->move = NULL_MOVE; @@ -565,8 +565,8 @@ int Negamax(int alpha, int beta, int depth, int cutnode, ThreadData* thread, PV* // Prob cut // If a relatively deep search from our TT doesn't say this node is // less than beta + margin, then we run a shallow search to look - int probBeta = beta + 197; - if (depth >= 5 && !ss->skip && abs(beta) < TB_WIN_BOUND && !(ttHit && ttDepth >= depth - 3 && ttScore < probBeta)) { + int probBeta = beta + 172; + if (depth >= 6 && !ss->skip && abs(beta) < TB_WIN_BOUND && !(ttHit && ttDepth >= depth - 3 && ttScore < probBeta)) { InitPCMovePicker(&mp, thread, probBeta > eval); while ((move = NextMove(&mp, board, 1))) { if (!IsLegal(move, board)) @@ -625,12 +625,12 @@ int Negamax(int alpha, int beta, int depth, int cutnode, ThreadData* thread, PV* if (!IsCap(move) && PromoPT(move) != QUEEN) { int lmrDepth = Max(1, depth - R); - if (!killerOrCounter && lmrDepth < 7 && history < -2658 * (depth - 1)) { + if (!killerOrCounter && lmrDepth < 5 && history < -2788 * (depth - 1)) { skipQuiets = 1; continue; } - if (!inCheck && lmrDepth < 10 && eval + 87 + 46 * lmrDepth <= alpha) + if (!inCheck && lmrDepth < 10 && eval + 81 + 46 * lmrDepth <= alpha) skipQuiets = 1; if (!SEE(board, move, STATIC_PRUNE[0][lmrDepth])) @@ -673,10 +673,10 @@ int Negamax(int alpha, int beta, int depth, int cutnode, ThreadData* thread, PV* // no score failed above sBeta, so this is singular if (score < sBeta) { - if (!isPV && score < sBeta - 50 && ss->de <= 6 && !IsCap(move)) { + if (!isPV && score < sBeta - 48 && ss->de <= 6 && !IsCap(move)) { extension = 3; ss->de = (ss - 1)->de + 1; - } else if (!isPV && score < sBeta - 17 && ss->de <= 6) { + } else if (!isPV && score < sBeta - 14 && ss->de <= 6) { extension = 2; ss->de = (ss - 1)->de + 1; } else { @@ -738,7 +738,7 @@ int Negamax(int alpha, int beta, int depth, int cutnode, ThreadData* thread, PV* if (score > alpha && R > 1) { // Credit to Viz (and lonfom) for the following modification of the zws // re-search depth. They can be found in SF as doDeeperSearch + doShallowerSearch - newDepth += (score > bestScore + 76); + newDepth += (score > bestScore + 69); newDepth -= (score < bestScore + newDepth); if (newDepth - 1 > lmrDepth) @@ -798,7 +798,7 @@ int Negamax(int alpha, int beta, int depth, int cutnode, ThreadData* thread, PV* // we're failing high if (alpha >= beta) { - UpdateHistories(ss, thread, move, depth + (bestScore > beta + 78), quiets, numQuiets, captures, numCaptures); + UpdateHistories(ss, thread, move, depth + (bestScore > beta + 77), quiets, numQuiets, captures, numCaptures); break; } } @@ -898,7 +898,7 @@ int Quiesce(int alpha, int beta, int depth, ThreadData* thread, SearchStack* ss) bestScore = eval; - futility = bestScore + 60; + futility = bestScore + 63; } int numQuiets = 0, numCaptures = 0; diff --git a/src/uci.c b/src/uci.c index 710b359e..0b78d721 100644 --- a/src/uci.c +++ b/src/uci.c @@ -178,8 +178,8 @@ void ParseGo(char* in, Board* board) { if (movesToGo == -1) { int total = Max(1, time + 50 * inc - 50 * MOVE_OVERHEAD); - Limits.alloc = Min(time * 0.3784, total * 0.0570); - Limits.max = Min(time * 0.7776 - MOVE_OVERHEAD, Limits.alloc * 5.8320) - 10; + Limits.alloc = Min(time * 0.4193, total * 0.0575); + Limits.max = Min(time * 0.9221 - MOVE_OVERHEAD, Limits.alloc * 5.9280) - 10; } else { int total = Max(1, time + movesToGo * inc - MOVE_OVERHEAD);