Skip to content

Commit

Permalink
v1: Tuned 44k games, use latest linrock smallnet.
Browse files Browse the repository at this point in the history
Bench: 1216398
  • Loading branch information
XInTheDark committed Dec 6, 2023
1 parent c234237 commit e15eec7
Show file tree
Hide file tree
Showing 2 changed files with 48 additions and 74 deletions.
2 changes: 1 addition & 1 deletion src/evaluate.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ extern std::string currentEvalFileName[2];
// for the build process (profile-build and fishtest) to work. Do not change the
// name of the macro, as it is used in the Makefile.
#define EvalFileDefaultNameBig "nn-0000000000a0.nnue"
#define EvalFileDefaultNameSmall "nn-ecb35f70ff2a.nnue"
#define EvalFileDefaultNameSmall "nn-9067e33176e8.nnue"

namespace NNUE {

Expand Down
120 changes: 47 additions & 73 deletions src/search.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -47,32 +47,6 @@

namespace Stockfish {

int
a1=125, a2=43, a3=1487, a4=976, a5=808, a6=291, a7=350, a8=1200, a9=361, a10=361, a11=1182,
b1=10, b2=15335, b3=110, b4=121, b5=14, b6=1449, b7=1449,
c1=474, c2=270, c3=174, c4=9, c5=321, c6=29462, c7=17257, c8=24, c9=281, c10=152, c11=14, c12=8, c13=168, c14=70,
d1=416, d2=7, d3=239, d4=291, d5=185, d6=6, d7=3645, d8=7836, d9=13, d10=62, d11=123, d12=77, d13=127, d14=26,
e1=24, e2=64, e3=57, e4=18, e5=11, e6=15, e7=19, e8=9, e9=4194, e10=4000, e11=7, e12=3848, e13=14200,
f1=50, f2=2, f3=2, f4=12, f5=13828, f6=11369, f7=6, f8=657, f9=10,
g1=200, g2=90, g3=168, g4=168;

TUNE(a1, a2, a3, a4, a5, a6, a7, a8, a9, a10, a11,
b1);
TUNE(SetRange(1, 30000), b2);
TUNE(b3, b4, b5, b6, b7,
c1, c2, c3, c4);
TUNE(SetRange(1, 600), c5);
TUNE(c6, c7, c8, c9);
TUNE(SetRange(1, 300), c10);
TUNE(c11, c12, c13, c14,
d1, d2, d3, d4, d5, d6, d7);
TUNE(SetRange(1, 15000), d8);
TUNE(d9, d10, d11, d12, d13, d14,
e1, e2, e3, e4, e5, e6, e7, e8, e9, e10, e11, e12);
TUNE(SetRange(1, 30000), e13);
TUNE(f1, f2, f3, f4, f5, f6, f7, f8, f9,
g1, g2, g3, g4);

namespace Search {

LimitsType Limits;
Expand Down Expand Up @@ -103,27 +77,27 @@ enum NodeType {

// Futility margin
Value futility_margin(Depth d, bool noTtCutNode, bool improving) {
return Value((a1 - a2 * noTtCutNode) * (d - improving));
return Value((116 - 44 * noTtCutNode) * (d - improving));
}

// Reductions lookup table initialized at startup
int Reductions[MAX_MOVES]; // [depth or moveNumber]

Depth reduction(bool i, Depth d, int mn, Value delta, Value rootDelta) {
int reductionScale = Reductions[d] * Reductions[mn];
return (reductionScale + a3 - int(delta) * a4 / int(rootDelta)) / 1024
+ (!i && reductionScale > a5);
return (reductionScale + 1346 - int(delta) * 896 / int(rootDelta)) / 1024
+ (!i && reductionScale > 880);
}

constexpr int futility_move_count(bool improving, Depth depth) {
return improving ? (3 + depth * depth) : (3 + depth * depth) / 2;
}

// History and stats update bonus, based on depth
int stat_bonus(Depth d) { return std::min(a6 * d - a7, a8); }
int stat_bonus(Depth d) { return std::min(268 * d - 352, 1153); }

// History and stats update malus, based on depth
int stat_malus(Depth d) { return std::min(a9 * d - a10, a11); }
int stat_malus(Depth d) { return std::min(400 * d - 354, 1201); }

// Add a small random component to draw evaluations to avoid 3-fold blindness
Value value_draw(const Thread* thisThread) {
Expand Down Expand Up @@ -393,12 +367,12 @@ void Thread::search() {

// Reset aspiration window starting size
Value avg = rootMoves[pvIdx].averageScore;
delta = Value(b1) + int(avg) * avg / b2;
delta = Value(9) + int(avg) * avg / 14847;
alpha = std::max(avg - delta, -VALUE_INFINITE);
beta = std::min(avg + delta, VALUE_INFINITE);

// Adjust optimism based on root move's averageScore (~4 Elo)
optimism[us] = b3 * avg / (std::abs(avg) + b4);
optimism[us] = 121 * avg / (std::abs(avg) + 109);
optimism[~us] = -optimism[us];

// Start with a small aspiration window and, in the case of a fail
Expand Down Expand Up @@ -772,7 +746,7 @@ Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, boo
// Use static evaluation difference to improve quiet move ordering (~4 Elo)
if (is_ok((ss - 1)->currentMove) && !(ss - 1)->inCheck && !priorCapture)
{
int bonus = std::clamp(-b5 * int((ss - 1)->staticEval + ss->staticEval), -b6, b7);
int bonus = std::clamp(-13 * int((ss - 1)->staticEval + ss->staticEval), -1555, 1452);
thisThread->mainHistory[~us][from_to((ss - 1)->currentMove)] << bonus;
if (type_of(pos.piece_on(prevSq)) != PAWN && type_of((ss - 1)->currentMove) != PROMOTION)
thisThread->pawnHistory[pawn_structure(pos)][pos.piece_on(prevSq)][prevSq] << bonus / 4;
Expand All @@ -791,7 +765,7 @@ Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, boo
// If eval is really low check with qsearch if it can exceed alpha, if it can't,
// return a fail low.
// Adjust razor margin according to cutoffCnt. (~1 Elo)
if (eval < alpha - c1 - (c2 - c3 * ((ss + 1)->cutoffCnt > 3)) * depth * depth)
if (eval < alpha - 472 - (284 - 165 * ((ss + 1)->cutoffCnt > 3)) * depth * depth)
{
value = qsearch<NonPV>(pos, ss, alpha - 1, alpha);
if (value < alpha)
Expand All @@ -800,24 +774,24 @@ Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, boo

// Step 8. Futility pruning: child node (~40 Elo)
// The depth condition is important for mate finding.
if (!ss->ttPv && depth < c4
if (!ss->ttPv && depth < 9
&& eval - futility_margin(depth, cutNode && !ss->ttHit, improving)
- (ss - 1)->statScore / c5
- (ss - 1)->statScore / 337
>= beta
&& eval >= beta && eval < c6 // smaller than TB wins
&& eval >= beta && eval < 29008 // smaller than TB wins
&& (!ttMove || ttCapture))
return (eval + beta) / 2;

// Step 9. Null move search with verification search (~35 Elo)
if (!PvNode && (ss - 1)->currentMove != MOVE_NULL && (ss - 1)->statScore < c7 && eval >= beta
&& eval >= ss->staticEval && ss->staticEval >= beta - c8 * depth + c9 && !excludedMove
if (!PvNode && (ss - 1)->currentMove != MOVE_NULL && (ss - 1)->statScore < 17496 && eval >= beta
&& eval >= ss->staticEval && ss->staticEval >= beta - 23 * depth + 304 && !excludedMove
&& pos.non_pawn_material(us) && ss->ply >= thisThread->nmpMinPly
&& beta > VALUE_TB_LOSS_IN_MAX_PLY)
{
assert(eval - beta >= 0);

// Null move dynamic reduction based on depth and eval
Depth R = std::min(int(eval - beta) / c10, 6) + depth / 3 + 4;
Depth R = std::min(int(eval - beta) / 144, 6) + depth / 3 + 4;

ss->currentMove = MOVE_NULL;
ss->continuationHistory = &thisThread->continuationHistory[0][0][NO_PIECE][0];
Expand All @@ -831,7 +805,7 @@ Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, boo
// Do not return unproven mate or TB scores
if (nullValue >= beta && nullValue < VALUE_TB_WIN_IN_MAX_PLY)
{
if (thisThread->nmpMinPly || depth < c11)
if (thisThread->nmpMinPly || depth < 15)
return nullValue;

assert(!thisThread->nmpMinPly); // Recursive verification is not allowed
Expand Down Expand Up @@ -861,10 +835,10 @@ Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, boo
return qsearch<PV>(pos, ss, alpha, beta);

// For cutNodes without a ttMove, we decrease depth by 2 if depth is high enough.
if (cutNode && depth >= c12 && !ttMove)
if (cutNode && depth >= 8 && !ttMove)
depth -= 2;

probCutBeta = beta + c13 - c14 * improving;
probCutBeta = beta + 163 - 67 * improving;

// Step 11. ProbCut (~10 Elo)
// If we have a good enough capture (or queen promotion) and a reduced search returns a value
Expand Down Expand Up @@ -922,7 +896,7 @@ Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, boo
moves_loop: // When in check, search starts here

// Step 12. A small Probcut idea, when we are in check (~4 Elo)
probCutBeta = beta + d1;
probCutBeta = beta + 425;
if (ss->inCheck && !PvNode && ttCapture && (tte->bound() & BOUND_LOWER)
&& tte->depth() >= depth - 4 && ttValue >= probCutBeta
&& abs(ttValue) < VALUE_TB_WIN_IN_MAX_PLY && abs(beta) < VALUE_TB_WIN_IN_MAX_PLY)
Expand Down Expand Up @@ -1005,18 +979,18 @@ Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, boo
if (capture || givesCheck)
{
// Futility pruning for captures (~2 Elo)
if (!givesCheck && lmrDepth < d2 && !ss->inCheck)
if (!givesCheck && lmrDepth < 7 && !ss->inCheck)
{
Piece capturedPiece = pos.piece_on(to_sq(move));
int futilityEval =
ss->staticEval + d3 + d4 * lmrDepth + PieceValue[capturedPiece]
ss->staticEval + 238 + 305 * lmrDepth + PieceValue[capturedPiece]
+ captureHistory[movedPiece][to_sq(move)][type_of(capturedPiece)] / 7;
if (futilityEval < alpha)
continue;
}

// SEE based pruning for captures and checks (~11 Elo)
if (!pos.see_ge(move, Value(-d5) * depth))
if (!pos.see_ge(move, Value(-187) * depth))
continue;
}
else
Expand All @@ -1027,25 +1001,25 @@ Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, boo
+ thisThread->pawnHistory[pawn_structure(pos)][movedPiece][to_sq(move)];

// Continuation history based pruning (~2 Elo)
if (lmrDepth < d6 && history < -d7 * depth)
if (lmrDepth < 6 && history < -3752 * depth)
continue;

history += 2 * thisThread->mainHistory[us][from_to(move)];

lmrDepth += history / d8;
lmrDepth += history / 7838;
lmrDepth = std::max(lmrDepth, -1);

// Futility pruning: parent node (~13 Elo)
if (!ss->inCheck && lmrDepth < d9
&& ss->staticEval + (bestValue < ss->staticEval - d10 ? d11 : d12)
+ d13 * lmrDepth
if (!ss->inCheck && lmrDepth < 14
&& ss->staticEval + (bestValue < ss->staticEval - 57 ? 124 : 71)
+ 118 * lmrDepth
<= alpha)
continue;

lmrDepth = std::max(lmrDepth, 0);

// Prune moves with negative SEE (~4 Elo)
if (!pos.see_ge(move, Value(-d14 * lmrDepth * lmrDepth)))
if (!pos.see_ge(move, Value(-26 * lmrDepth * lmrDepth)))
continue;
}
}
Expand All @@ -1065,11 +1039,11 @@ Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, boo
// so changing them requires tests at these types of time controls.
// Recursive singular search is avoided.
if (!rootNode && move == ttMove && !excludedMove
&& depth >= 4 - (thisThread->completedDepth > e1) + 2 * (PvNode && tte->is_pv())
&& depth >= 4 - (thisThread->completedDepth > 27) + 2 * (PvNode && tte->is_pv())
&& abs(ttValue) < VALUE_TB_WIN_IN_MAX_PLY && (tte->bound() & BOUND_LOWER)
&& tte->depth() >= depth - 3)
{
Value singularBeta = ttValue - (e2 + e3 * (ss->ttPv && !PvNode)) * depth / 64;
Value singularBeta = ttValue - (66 + 58 * (ss->ttPv && !PvNode)) * depth / 64;
Depth singularDepth = newDepth / 2;

ss->excludedMove = move;
Expand All @@ -1083,10 +1057,10 @@ Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, boo
singularQuietLMR = !ttCapture;

// Avoid search explosion by limiting the number of double extensions
if (!PvNode && value < singularBeta - e4 && ss->doubleExtensions <= e5)
if (!PvNode && value < singularBeta - 17 && ss->doubleExtensions <= 11)
{
extension = 2;
depth += depth < e6;
depth += depth < 15;
}
}

Expand All @@ -1110,26 +1084,26 @@ Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, boo

// If we are on a cutNode but the ttMove is not assumed to fail high over current beta (~1 Elo)
else if (cutNode)
extension = depth < e7 ? -2 : -1;
extension = depth < 19 ? -2 : -1;

// If the ttMove is assumed to fail low over the value of the reduced search (~1 Elo)
else if (ttValue <= value)
extension = -1;
}

// Check extensions (~1 Elo)
else if (givesCheck && depth > e8)
else if (givesCheck && depth > 10)
extension = 1;

// Quiet ttMove extensions (~1 Elo)
else if (PvNode && move == ttMove && move == ss->killers[0]
&& (*contHist[0])[movedPiece][to_sq(move)] >= e9)
&& (*contHist[0])[movedPiece][to_sq(move)] >= 4325)
extension = 1;

// Recapture extensions (~1 Elo)
else if (PvNode && move == ttMove && to_sq(move) == prevSq
&& captureHistory[movedPiece][to_sq(move)][type_of(pos.piece_on(to_sq(move)))]
> e10)
> 4146)
extension = 1;
}

Expand All @@ -1153,7 +1127,7 @@ Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, boo
r -= cutNode && tte->depth() >= depth ? 3 : 2;

// Decrease reduction if opponent's move count is high (~1 Elo)
if ((ss - 1)->moveCount > e11)
if ((ss - 1)->moveCount > 7)
r--;

// Increase reduction for cut nodes (~3 Elo)
Expand Down Expand Up @@ -1188,10 +1162,10 @@ Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, boo
ss->statScore = 2 * thisThread->mainHistory[us][from_to(move)]
+ (*contHist[0])[movedPiece][to_sq(move)]
+ (*contHist[1])[movedPiece][to_sq(move)]
+ (*contHist[3])[movedPiece][to_sq(move)] - e12;
+ (*contHist[3])[movedPiece][to_sq(move)] - 3817;

// Decrease/increase reduction for moves with a good/bad history (~25 Elo)
r -= ss->statScore / e13;
r -= ss->statScore / 14767;

// Step 17. Late moves reduction / extension (LMR, ~117 Elo)
// We use various heuristics for the sons of a node after the first son has
Expand All @@ -1214,7 +1188,7 @@ Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, boo
{
// 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 + f1 + f2 * newDepth); // (~1 Elo)
const bool doDeeperSearch = value > (bestValue + 53 + 2 * newDepth); // (~1 Elo)
const bool doShallowerSearch = value < bestValue + newDepth; // (~2 Elo)

newDepth += doDeeperSearch - doShallowerSearch;
Expand Down Expand Up @@ -1329,7 +1303,7 @@ Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, boo
else
{
// Reduce other moves if we have found at least one score improvement (~2 Elo)
if (depth > f3 && depth < f4 && beta < f5 && value > -f6)
if (depth > 2 && depth < 12 && beta < 13782 && value > -11541)
depth -= 2;

assert(depth > 0);
Expand Down Expand Up @@ -1368,8 +1342,8 @@ Value search(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth, boo
// Bonus for prior countermove that caused the fail low
else if (!priorCapture && prevSq != SQ_NONE)
{
int bonus = (depth > f7) + (PvNode || cutNode) + (bestValue < alpha - f8)
+ ((ss - 1)->moveCount > f9);
int bonus = (depth > 6) + (PvNode || cutNode) + (bestValue < alpha - 656)
+ ((ss - 1)->moveCount > 10);
update_continuation_histories(ss - 1, pos.piece_on(prevSq), prevSq,
stat_bonus(depth) * bonus);
thisThread->mainHistory[~us][from_to((ss - 1)->currentMove)]
Expand Down Expand Up @@ -1501,7 +1475,7 @@ Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth) {
if (bestValue > alpha)
alpha = bestValue;

futilityBase = ss->staticEval + g1;
futilityBase = ss->staticEval + 182;
}

const PieceToHistory* contHist[] = {(ss - 1)->continuationHistory,
Expand Down Expand Up @@ -1581,7 +1555,7 @@ Value qsearch(Position& pos, Stack* ss, Value alpha, Value beta, Depth depth) {
continue;

// Do not search moves with bad enough SEE values (~5 Elo)
if (!pos.see_ge(move, Value(-g2)))
if (!pos.see_ge(move, Value(-77)))
continue;
}

Expand Down Expand Up @@ -1717,15 +1691,15 @@ void update_all_stats(const Position& pos,

if (!pos.capture_stage(bestMove))
{
int bestMoveBonus = bestValue > beta + g3 ? quietMoveBonus // larger bonus
int bestMoveBonus = bestValue > beta + 173 ? quietMoveBonus // larger bonus
: stat_bonus(depth); // smaller bonus

// Increase stats for the best move in case it was a quiet move
update_quiet_stats(pos, ss, bestMove, bestMoveBonus);
thisThread->pawnHistory[pawn_structure(pos)][moved_piece][to_sq(bestMove)]
<< quietMoveBonus;

int moveMalus = bestValue > beta + g4 ? quietMoveMalus // larger malus
int moveMalus = bestValue > beta + 165 ? quietMoveMalus // larger malus
: stat_malus(depth); // smaller malus

// Decrease stats for all non-best quiet moves
Expand Down

0 comments on commit e15eec7

Please sign in to comment.