Skip to content

Commit

Permalink
Futility Pruning (#42)
Browse files Browse the repository at this point in the history
ELO   | 16.69 +- 8.79 (95%)
SPRT  | 8.0+0.08s Threads=1 Hash=16MB
LLR   | 3.02 (-2.94, 2.94) [0.00, 5.00]
GAMES | N: 3520 W: 1115 L: 946 D: 1459
https://engineprogramming.pythonanywhere.com/test/221/

Bench: 10504983
  • Loading branch information
crippa1337 authored Apr 23, 2023
1 parent 173201f commit f59a6f0
Show file tree
Hide file tree
Showing 5 changed files with 48 additions and 18 deletions.
11 changes: 11 additions & 0 deletions CHANGELOG.txt
Original file line number Diff line number Diff line change
Expand Up @@ -271,4 +271,15 @@ Move RFP (#40)
GAMES | N: 4024 W: 1233 L: 1066 D: 1725
https://engineprogramming.pythonanywhere.com/test/167/

====================================================================================
3.5 [April 23 2023]

Futility Pruning (#42)

ELO | 16.69 +- 8.79 (95%)
SPRT | 8.0+0.08s Threads=1 Hash=16MB
LLR | 3.02 (-2.94, 2.94) [0.00, 5.00]
GAMES | N: 3520 W: 1115 L: 946 D: 1459
https://engineprogramming.pythonanywhere.com/test/221/

====================================================================================
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[package]
name = "svart"
version = "3.4.0"
version = "3.5.0"
edition = "2021"

[dependencies]
Expand Down
49 changes: 34 additions & 15 deletions src/engine/search.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,9 @@ use std::time::Instant;
static LMR: Lazy<LMRTable> = Lazy::new(LMRTable::new);
const RFP_MARGIN: i32 = 75;
const LMP_TABLE: [usize; 4] = [0, 5, 8, 18];
const FP_COEFFICIENT: i32 = 100;
const FP_MARGIN: i32 = 75;
const FP_DEPTH: i32 = 6;

pub struct StackEntry {
pub eval: i32,
Expand Down Expand Up @@ -149,17 +152,12 @@ impl Search {
return self.qsearch::<PV>(board, alpha, beta, ply);
}

// Static eval used for pruning
let eval;

let tt_entry = self.tt.probe(hash_key);
let tt_hit = tt_entry.key == hash_key as u16;
let tt_score = self.tt.score_from_tt(tt_entry.score, ply) as i32;
let mut tt_move: Option<Move> = None;

if tt_hit {
// Use the TT score if available since eval is expensive
// and any score from the TT is better than the static eval
let tt_score = self.tt.score_from_tt(tt_entry.score, ply) as i32;
eval = tt_score;
tt_move = Some(PackedMove::unpack(tt_entry.mv));

if !PV && i32::from(tt_entry.depth) >= depth {
Expand All @@ -173,10 +171,19 @@ impl Search {
return tt_score;
}
}
} else {
eval = self.nnue.evaluate(stm);
}

let eval = if tt_hit {
// Use the TT score if available since eval is expensive
// and any score from the TT is better than the static eval
tt_score
} else if in_check {
// If we're in check, it's unstable to use the static eval
-INFINITY
} else {
self.nnue.evaluate(stm)
};

// Improving
// If the previous eval from our point of view is worse than what it currently is
// then we are improving our position. This is used in some heuristics to improve pruning.
Expand Down Expand Up @@ -226,7 +233,7 @@ impl Search {
let mut quiet_moves = StaticVec::<Option<Move>, MAX_MOVES_POSITION>::new(None);
let mut picker = Picker::new(move_list);

let lmr_depth = if PV { 5 } else { 3 };
let lmr_threshold = if PV { 5 } else { 3 };
let mut quiets_checked = 0;
let quiets_to_check = match depth {
d @ 1..=3 => LMP_TABLE[d as usize],
Expand All @@ -238,13 +245,25 @@ impl Search {

while let Some(mv) = picker.pick_move() {
let is_quiet = is_quiet(board, mv);
let lmr_reduction = LMR.reduction(depth, moves_played.max(1));
let lmr_depth = 0.max(depth - lmr_reduction);

if is_quiet {
quiets_checked += 1;

// Late Move Pruning (LMP)
// If we have searched too many moves, we stop searching here
if !PV && !in_check && quiets_checked >= quiets_to_check {
break;
if !PV && !in_check && best_score > TB_LOSS_IN_PLY {
// Late Move Pruning (LMP)
// If we have searched too many moves, we stop searching here
if quiets_checked >= quiets_to_check {
break;
}

// Futility Pruning (FP)
// If static eval plus a margin can't beat alpha, we stop searching here
let fp_margin = lmr_depth * FP_COEFFICIENT + FP_MARGIN;
if lmr_depth < FP_DEPTH && eval + fp_margin <= alpha {
break;
}
}

quiet_moves.push(Some(mv));
Expand All @@ -269,7 +288,7 @@ impl Search {
and can be searched with a reduced depth, if they beat alpha
we do a full re-search.
*/
let r = if depth >= 3 && moves_played > lmr_depth {
let r = if depth >= 3 && moves_played > lmr_threshold {
// Probe LMR table (src/lmr.rs)
let mut r = LMR.reduction(depth, moves_played);

Expand Down
2 changes: 1 addition & 1 deletion src/uci/handler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ pub enum SearchType {
}

fn id() {
println!("id name Svart 3.4");
println!("id name Svart 3.5");
println!("id author crippa");
}

Expand Down

0 comments on commit f59a6f0

Please sign in to comment.