Skip to content

Commit

Permalink
mix8 search tuning merge
Browse files Browse the repository at this point in the history
Passed f15 LTC:
Book: f15-base-8k
TC: 60+0.6
Total/Win/Draw/Lose: 3346 / 993 / 1527 / 826
PTNML: 76 / 352 / 688 / 443 / 114
WinRate: 52.50%
ELO: 16.69[7.67, 25.72]
LOS: 99.98
LLR: 3.10[-2.94, 2.94]

Passed f20 LTC:
Book: f20-base-8k
TC: 60+0.6
Total/Win/Draw/Lose: 7026 / 3641 / 18 / 3367
PTNML: 646 / 7 / 2068 / 11 / 781
WinRate: 51.95%
ELO: 12.72[4.02, 21.36]
LOS: 99.79
LLR: 3.22[-2.94, 2.94]

Passed s15 LTC:
Book: s15-base-24k
TC: 60+0.6
Total/Win/Draw/Lose: 2082 / 560 / 1109 / 413
PTNML: 34 / 193 / 480 / 260 / 74
WinRate: 53.53%
ELO: 23.97[13.62, 34.43]
LOS: 100.00
LLR: 2.99[-2.94, 2.94]

Passed r15 LTC:
Book: r15-base-40k
TC: 60+0.6
Total/Win/Draw/Lose: 5622 / 2080 / 1665 / 1877
PTNML: 256 / 502 / 1159 / 571 / 323
WinRate: 51.81%
ELO: 11.78[3.79, 19.74]
LOS: 99.80
LLR: 3.10[-2.94, 2.94]

bench efdde667
bench (msvc) 8888d4c3
  • Loading branch information
dhbloo committed Aug 29, 2023
1 parent a97c2ab commit 8a824ab
Show file tree
Hide file tree
Showing 4 changed files with 122 additions and 95 deletions.
148 changes: 91 additions & 57 deletions Rapfi/search/ab/parameter.h
Original file line number Diff line number Diff line change
Expand Up @@ -34,15 +34,16 @@ constexpr int MAX_PLY = 256;
// -------------------------------------------------
// Depth & Value Constants

constexpr Value MARGIN_INFINITE = Value(INT16_MAX);
constexpr Depth ASPIRATION_DEPTH = 5.0f;
constexpr Depth IID_DEPTH = 14.8f;
constexpr Depth IIR_REDUCTION = 0.9f;
constexpr Depth IIR_REDUCTION_PV = 0.35f;
constexpr Depth SE_DEPTH = 7.8f;
constexpr Depth SE_TTE_DEPTH = 1.9f;
constexpr Depth RAZOR_PRUN_DEPTH = 3.0f;
constexpr Depth TRIVIAL_PRUN_DEPTH = 3.9f;
constexpr Value MARGIN_INFINITE = Value(INT16_MAX);
constexpr Depth ASPIRATION_DEPTH = 5.0f;
constexpr Depth IID_DEPTH = 14.8f;
constexpr Depth IIR_REDUCTION = 0.9f;
constexpr Depth IIR_REDUCTION_PV = 0.35f;
constexpr Depth SE_DEPTH = 7.8f;
constexpr Depth SE_TTE_DEPTH = 1.9f;
constexpr Depth TRIVIAL_PRUN_DEPTH = 3.9f;
constexpr Depth SE_EXTRA_MAX_DEPTH = 12.0f;
constexpr Depth LMR_EXTRA_MAX_DEPTH = 5.0f;

// -------------------------------------------------
// Dynamic margin & reduction functions/LUTs
Expand All @@ -56,53 +57,64 @@ constexpr Value nextAspirationWindowDelta(Value prevValue, Value prevDelta = VAL
}

/// Razoring depth & margins
template <Rule R>
constexpr Value razorMargin(Depth d)
{
return d < 3.77f ? static_cast<Value>(std::max(int(0.169f * d * d + 26 * d) + 26, 0))
: MARGIN_INFINITE;
}

/// Razoring verification margin
constexpr Value razorVerifyMargin(Depth d)
{
return razorMargin(d - 3.27f);
return d < 2.7f ? Value(std::max(int(0.18f * d * d + 17 * d) + 18, 0)) : MARGIN_INFINITE;
}

/// Static futility pruning depth & margins
template <Rule R>
constexpr Value futilityMargin(Depth d, bool noTTCutNode, bool improving)
{
return Value(std::max(int((55 - 12 * noTTCutNode) * (d - improving)), 0));
constexpr int FutilityScale[RULE_NB] = {63, 69, 73};
return Value(std::max(int((FutilityScale[R] - 13 * noTTCutNode) * (d - improving)), 0));
}

/// Null move pruning margin
template <Rule R>
constexpr Value nullMoveMargin(Depth d)
{
return d >= 9.75f ? Value(488 - std::min(26 * int(d), 370)) : MARGIN_INFINITE;
constexpr int NMMBias[RULE_NB] = {585, 484, 573};
constexpr int NMMScale[RULE_NB] = {27, 26, 29};
return d >= 10 ? Value(NMMBias[R] - std::min(NMMScale[R] * int(d), 315)) : MARGIN_INFINITE;
}

/// Null move search depth reduction. The result of a null move will be
/// tested using reduced depth search.
template <Rule R>
constexpr Depth nullMoveReduction(Depth d)
{
return 5.0f + 0.14f * d;
constexpr float NMRBias[RULE_NB] = {3.67f, 3.66f, 4.44f};
constexpr float NMRScale[RULE_NB] = {0.135f, 0.134f, 0.157f};
return NMRBias[R] + NMRScale[R] * d;
}

/// Internal iterative deepening depth reduction.
template <Rule R>
constexpr Depth iidDepthReduction(Depth d)
{
return std::max(6.9f + 0.54f * d, 7.2f);
constexpr Depth IDRBias[RULE_NB] = {7.6f, 7.9f, 9.1f};
constexpr Depth IDRScale[RULE_NB] = {0.67f, 0.57f, 0.64f};
return IDRBias[R] + IDRScale[R] * d;
}

/// Fail high reduction margin
template <Rule R>
constexpr Value failHighMargin(Depth d, int oppo4)
{
return Value(34 * int(d) + 86 * bool(oppo4));
constexpr int FHBias[RULE_NB] = {-10, -12, -8};
constexpr int FHScale[RULE_NB] = {18, 16, 16};
return Value(FHBias[R] + FHScale[R] * int(d) + 88 * bool(oppo4));
}

/// Fail low reduction margin
template <Rule R>
constexpr Value failLowMargin(Depth d)
{
return Value(87 + int(49 * d));
constexpr int FLBias[RULE_NB] = {89, 82, 104};
constexpr int FLScale[RULE_NB] = {58, 54, 43};
return Value(FLBias[R] + int(FLScale[R] * d));
}

// Lookup tables used for move count based pruning, initialized at startup
Expand Down Expand Up @@ -147,78 +159,100 @@ constexpr Value qvcfDeltaMargin(Rule rule, Depth d) // note: d <= 0

/// LMR move count. For non-PV all node, moves that exceeds late move count
/// will be searched will late move reduction even without other condition.
template <Rule R>
constexpr int lateMoveCount(Depth d, bool improving)
{
return 1 + 2 * improving + int((improving ? 1.68f : 1.17f) * d);
constexpr float LMC[RULE_NB][2] = {
{0.82f, 1.48f},
{0.91f, 1.06f},
{0.66f, 1.45f},
};
return 1 + 2 * improving + int(LMC[R][improving] * d);
}

/// Extension for full-depth search when reduced LMR search fails high
constexpr int lmrFullSearchExtension(Depth newDepth,
Depth searchedDepth,
Value value,
Value alpha,
Value bestValue)
{
bool doDeeperSearch = value > (alpha + 70 + Value(15 * (newDepth - searchedDepth)));
bool doEvenDeeperSearch = value > (alpha + 350 + Value(30 * (newDepth - searchedDepth)));
bool doShallowerSearch = value < bestValue + Value(newDepth);
template <Rule R>
constexpr int
lmrExtension(Depth newDepth, Depth searchedDepth, Value value, Value alpha, Value bestValue)
{
constexpr int LMRExt1Bias[RULE_NB] = {37, 31, 37};
constexpr int LMRExt2Bias[RULE_NB] = {349, 344, 258};

bool doDeeperSearch = value > (alpha + LMRExt1Bias[R] + Value(12 * (newDepth - searchedDepth)));
bool doEvenDeeperSearch =
value > (alpha + LMRExt2Bias[R] + Value(32 * (newDepth - searchedDepth)));
bool doShallowerSearch = value < bestValue + Value(newDepth);
return doDeeperSearch + doEvenDeeperSearch - doShallowerSearch;
}

/// Init Reductions table according to num threads.
inline void initReductionLUT(std::array<Depth, MAX_MOVES + 1> &lut, int numThreads = 1)
inline void initReductionLUT(std::array<Depth, MAX_MOVES + 1> (&lut)[RULE_NB], int numThreads = 1)
{
double factor = 0.786;
double threadBias = 0.1 * std::log(numThreads);
lut[0] = 0.0f;
for (size_t i = 1; i < lut.size(); i++)
lut[i] = float(factor * (std::log(i) + threadBias));
constexpr double Factor[RULE_NB] = {1.0, 0.97, 0.90};
double threadBias = 0.1 * std::log(numThreads);
for (int r = 0; r < RULE_NB; r++) {
lut[r][0] = 0.0f;
for (size_t i = 1; i < lut[r].size(); i++)
lut[r][i] = float(Factor[r] * (std::log(i) + threadBias));
}
}

/// Basic depth reduction in LMR search
template <bool PvNode>
constexpr Depth reduction(const std::array<Depth, MAX_MOVES + 1> &lut,
Depth d,
int moveCount,
int improvement,
Value delta,
Value rootDelta)
template <Rule R, bool PvNode>
constexpr Depth reduction(const std::array<Depth, MAX_MOVES + 1> (&lut)[RULE_NB],
Depth d,
int moveCount,
int improvement,
Value delta,
Value rootDelta)
{
assert(d > 0.0f);
assert(moveCount > 0 && moveCount < lut.size());
Depth r = lut[(int)d] * lut[moveCount];
Depth r = lut[R][(int)d] * lut[R][moveCount];
if constexpr (PvNode)
return std::max(r - Depth(delta) / Depth(rootDelta), 0.0f);
else
return r + (improvement <= 0 && r > 1.0f);
}

constexpr Depth CR1[RULE_NB] = {0.0841f, 0.01f * 9.0f, 0.01f * 7.200f};
constexpr Depth CR2[RULE_NB] = {0.0479f, 0.01f * 4.0f, 0.01f * 3.628f};
constexpr Depth CR3[RULE_NB] = {0.0211f, 0.01f * 2.0f, 0.01f * 1.950f};
constexpr Depth CR4[RULE_NB] = {0.0056f, 0.01f * 0.7f, 0.01f * 0.681f};
constexpr Depth PolicyReductionScale[RULE_NB] = {2.42f, 3.2f, 3.469f};
constexpr Depth PolicyReductionBias[RULE_NB] = {3.67f, 5.0f, 5.205f};
constexpr Depth PolicyReductionMax[RULE_NB] = {4.00f, 4.0f, 4.047f};

/// Complexity reduction factor based on move type.
template <Rule R>
constexpr Depth complexityReduction(bool trivialMove, bool importantMove, bool distract)
{
constexpr Depth CR1[RULE_NB] = {0.0968f, 0.079f, 0.083f};
constexpr Depth CR2[RULE_NB] = {0.0385f, 0.026f, 0.032f};
constexpr Depth CR3[RULE_NB] = {0.0222f, 0.022f, 0.021f};
constexpr Depth CR4[RULE_NB] = {0.0055f, 0.007f, 0.007f};
return (trivialMove ? (distract ? CR1 : CR2) : !importantMove ? CR3 : CR4)[R];
}

/// Policy depth reduction based on normalized policy score.
template <Rule R>
constexpr Depth policyReduction(float normalizedPolicyScore)
{
constexpr Depth PolicyReductionScale[RULE_NB] = {3.14f, 3.63f, 3.40f};
constexpr Depth PolicyReductionBias[RULE_NB] = {2.21f, 3.08f, 4.25f};
constexpr Depth PolicyReductionMax[RULE_NB] = {5.00f, 3.77f, 4.84f};

Depth r = PolicyReductionBias[R] - PolicyReductionScale[R] * normalizedPolicyScore;
return std::min(std::max(r, 0.0f), PolicyReductionMax[R]);
}

/// Policy pruning score at given depth. Moves lower than this are pruned at low depth.
template <Rule R>
inline int policyPruningScore(Depth d)
{
return 339 - int(d * 57);
constexpr int PPBias[RULE_NB] = {394, 454, 484};
constexpr int PPScale[RULE_NB] = {46, 51, 53};
return PPBias[R] - int(d * PPScale[R]);
}

/// Policy reduction score at given depth. Moves lower than this will do lmr.
template <Rule R>
inline int policyReductionScore(Depth d)
{
return 457;
constexpr int PRBias[RULE_NB] = {489, 506, 581};
return PRBias[R];
}

} // namespace Search::AB
63 changes: 28 additions & 35 deletions Rapfi/search/ab/search.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -837,26 +837,22 @@ Value search(Board &board, SearchStack *ss, Value alpha, Value beta, Depth depth
}

// Step 7. Razoring with VCF (~55 elo)
if (!PvNode && eval + razorMargin(depth) < alpha) {
Value ralpha = alpha - razorVerifyMargin(depth);
Value v = vcfsearch<Rule, NonPV>(board, ss, ralpha, ralpha + 1);

if (depth < RAZOR_PRUN_DEPTH || v <= ralpha)
return v;
if (!PvNode && eval + razorMargin<Rule>(depth) < alpha) {
return vcfsearch<Rule, NonPV>(board, ss, alpha, alpha + 1);
}

// Step 8. Futility pruning: child node (~70 elo)
if (!PvNode && eval < VALUE_MATE_IN_MAX_PLY // Do not return unproven wins
&& beta > VALUE_MATED_IN_MAX_PLY // Confirm non-losing move exists
&& eval - futilityMargin(depth - 1, cutNode && !ttHit, improvement > 0) >= beta
&& eval - futilityMargin<Rule>(depth - 1, cutNode && !ttHit, improvement > 0) >= beta
&& !((ss - 2)->moveP4[self] >= E_BLOCK4 && (ss - 4)->moveP4[self] >= E_BLOCK4))
return eval;

// Step 9. Null move pruning (~35 elo)
if (!PvNode && !oppo4 && !skipMove && eval >= beta
&& board.getLastMove() != Pos::PASS // No consecutive pass moves
&& ss->staticEval >= beta + nullMoveMargin(depth)) {
Depth r = nullMoveReduction(depth);
&& ss->staticEval >= beta + nullMoveMargin<Rule>(depth)) {
Depth r = nullMoveReduction<Rule>(depth);
ss->currentMove = Pos::PASS;

board.doPassMove();
Expand Down Expand Up @@ -896,7 +892,7 @@ Value search(Board &board, SearchStack *ss, Value alpha, Value beta, Depth depth
depth -= IIR_REDUCTION;

// We only need best move from the iid search, so we just discard its result
search<Rule, NT>(board, ss, alpha, beta, depth - iidDepthReduction(depth), cutNode);
search<Rule, NT>(board, ss, alpha, beta, depth - iidDepthReduction<Rule>(depth), cutNode);

// Get best move from transposition table, which should be just written by the search.
Value tmpEval;
Expand All @@ -922,12 +918,12 @@ Value search(Board &board, SearchStack *ss, Value alpha, Value beta, Depth depth

// Fail-High reduction (~50 elo)
// Indicate cutNode that will probably fail high if current eval is far above beta
bool likelyFailHigh = !PvNode && cutNode && eval >= beta + failHighMargin(depth, oppo4);
bool likelyFailHigh = !PvNode && cutNode && eval >= beta + failHighMargin<Rule>(depth, oppo4);

// Indicate PvNodes that will probably fail low if node was searched with non-PV search
// at depth equal or greater to current depth and result of this search was far below alpha
bool likelyFailLow = PvNode && ttHit && (ttBound & BOUND_UPPER) && ttDepth >= depth
&& ttValue < alpha + failLowMargin(depth);
&& ttValue < alpha + failLowMargin<Rule>(depth);

MovePicker mp(Rule,
board,
Expand Down Expand Up @@ -1056,7 +1052,7 @@ Value search(Board &board, SearchStack *ss, Value alpha, Value beta, Depth depth
if (value < singularBeta) {
// Extend two ply if current non-pv position is highly singular.
if (!PvNode && value < singularBeta - doubleSEMargin(depth)
&& ss->doubleExtensionCount < searchData->rootDepth / 4)
&& ss->extraExtension < SE_EXTRA_MAX_DEPTH)
extension = 2.0f;
else
extension = 1.0f;
Expand All @@ -1076,7 +1072,7 @@ Value search(Board &board, SearchStack *ss, Value alpha, Value beta, Depth depth

// Additional extension for near B4 ttmove
if (ss->moveP4[self] >= E_BLOCK4 && distSelf <= 6)
extension += (distSelf <= 4 ? 0.19f : 0.05f);
extension += (distSelf <= 4 ? 0.20f : 0.05f);
}

// Fail high reduction
Expand All @@ -1091,9 +1087,9 @@ Value search(Board &board, SearchStack *ss, Value alpha, Value beta, Depth depth
}

// Calculate new depth for this move
Depth newDepth = depth - 1.0f + extension;
ss->currentMove = move;
ss->doubleExtensionCount = (ss - 1)->doubleExtensionCount + (extension >= 2.0f);
Depth newDepth = depth - 1.0f + extension;
ss->currentMove = move;
ss->extraExtension = (ss - 1)->extraExtension + std::max(extension - 1.0f, 0.0f);

// Step 14. Make the move
board.move<Rule>(move);
Expand All @@ -1106,25 +1102,21 @@ Value search(Board &board, SearchStack *ss, Value alpha, Value beta, Depth depth
&& (!importantMove // do LMR for non important move
|| distract // do LMR for distract move
|| cutNode // do LMR for all moves in cut node
|| moveCount >= lateMoveCount(depth, improvement > 0) // do LMR for late move
|| mp.hasPolicyScore() // do LMR for low policy
|| moveCount >= lateMoveCount<Rule>(depth, improvement > 0) // do LMR for late move
|| mp.hasPolicyScore() // do LMR for low policy
&& mp.curMoveScore() < policyReductionScore<Rule>(depth))) {
Value delta = beta - alpha;
Depth r = reduction<PvNode>(searcher->reductions,
depth,
moveCount,
improvement,
delta,
searchData->rootDelta);
Depth r = reduction<Rule, PvNode>(searcher->reductions,
depth,
moveCount,
improvement,
delta,
searchData->rootDelta);

// Policy based reduction
if (mp.hasPolicyScore()) {
const float Scale =
PolicyReductionScale[Rule] * (0.1f / Evaluation::PolicyBuffer::ScoreScale);
r += std::clamp(PolicyReductionBias[Rule] - mp.curMoveScore() * Scale,
0.0f,
PolicyReductionMax[Rule]);
}
if (mp.hasPolicyScore())
r += policyReduction<Rule>(mp.curMoveScore()
* (0.1f / Evaluation::PolicyBuffer::ScoreScale));

// Dynamic reduction based on complexity
r += complexity * complexityReduction<Rule>(trivialMove, importantMove, distract);
Expand Down Expand Up @@ -1170,11 +1162,12 @@ Value search(Board &board, SearchStack *ss, Value alpha, Value beta, Depth depth
value = -search<Rule, NonPV>(board, ss + 1, -(alpha + 1), -alpha, d, true);

if (value > alpha && d < newDepth) {
Depth ext = lmrFullSearchExtension(newDepth, d, value, alpha, bestValue);
if (ss->doubleExtensionCount > searchData->rootDepth / 4)
Depth ext = lmrExtension<Rule>(newDepth, d, value, alpha, bestValue);
// Do not allow more extension if extra extension is already high
if (ss->extraExtension >= LMR_EXTRA_MAX_DEPTH)
ext = std::min(ext, 1.0f);
else
ss->doubleExtensionCount += static_cast<int>(ext > 1.0f);
ss->extraExtension += std::max(ext - 1.0f, 0.0f);
newDepth += ext;
}

Expand Down
2 changes: 1 addition & 1 deletion Rapfi/search/ab/searcher.h
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ class ABSearcher : public Searcher
Value previousBestValue; // (keep for one game)

/// Lookup tables used for reduction/purning, where index is depth or moveCount.
std::array<Depth, MAX_MOVES + 1> reductions;
std::array<Depth, MAX_MOVES + 1> reductions[RULE_NB];

~ABSearcher() = default;
std::unique_ptr<SearchData> makeSearchData(SearchThread &th) override
Expand Down
Loading

0 comments on commit 8a824ab

Please sign in to comment.