Skip to content

Commit

Permalink
separate late move reductions from futility pruning
Browse files Browse the repository at this point in the history
  • Loading branch information
brunocodutra committed Dec 31, 2024
1 parent a9046ed commit eeec246
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 29 deletions.
20 changes: 10 additions & 10 deletions lib/search/driver.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,12 +43,12 @@ impl Driver {
f: F,
) -> Result<(Move, Pv<N>), Interrupted>
where
F: Fn(Score, Move, Value) -> Result<Pv<N>, ControlFlow> + Sync,
F: Fn(Score, Move, Value, usize) -> Result<Pv<N>, ControlFlow> + Sync,
{
match self {
Self::Sequential => {
for &(m, gain) in moves.iter().rev() {
match f(tail.score(), m, gain) {
for (idx, &(m, gain)) in moves.iter().rev().enumerate() {
match f(tail.score(), m, gain, idx) {
Err(ControlFlow::Break) => break,
Err(ControlFlow::Continue) => continue,
Err(ControlFlow::Interrupt(e)) => return Err(e),
Expand All @@ -68,19 +68,19 @@ impl Driver {
let score = AtomicI16::new(tail.score().get());
let (head, tail, _) = moves
.par_iter()
.enumerate()
.rev()
.map(
|(idx, &(m, gain))| match f(Score::new(score.load(Relaxed)), m, gain) {
.enumerate()
.map(|(idx, &(m, gain))| {
match f(Score::new(score.load(Relaxed)), m, gain, idx) {
Err(ControlFlow::Break) => None,
Err(ControlFlow::Continue) => Some(Ok(None)),
Err(ControlFlow::Interrupt(e)) => Some(Err(e)),
Ok(partial) => {
score.fetch_max(partial.score().get(), Relaxed);
Some(Ok(Some((m, partial, idx))))
Some(Ok(Some((m, partial, usize::MAX - idx))))
}
},
)
}
})
.while_some()
.chain([Ok(Some((head, tail, usize::MAX)))])
.try_reduce(
Expand Down Expand Up @@ -116,7 +116,7 @@ mod tests {
});

assert_eq!(
Driver::new(c).drive(h, t, &ms, |_, _, v| Ok(Pv::new(v.saturate(), []))),
Driver::new(c).drive(h, t, &ms, |_, _, v, _| Ok(Pv::new(v.saturate(), []))),
Ok((head, tail))
)
}
Expand Down
52 changes: 33 additions & 19 deletions lib/search/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -92,17 +92,6 @@ impl Engine {
(bounds.start.max(lower), bounds.end.min(upper))
}

/// An implementation of [reverse futility pruning].
///
/// [reverse futility pruning]: https://www.chessprogramming.org/Reverse_Futility_Pruning
fn rfp(&self, surplus: Score, draft: Depth) -> Option<Depth> {
match surplus.get() {
..0 => None,
0..680 => Some(draft - (surplus + 40) / 120),
680.. => Some(draft - 6),
}
}

/// An implementation of [null move pruning].
///
/// [null move pruning]: https://www.chessprogramming.org/Null_Move_Pruning
Expand All @@ -123,10 +112,21 @@ impl Engine {
}
}

/// An implementation of [late move pruning].
/// An implementation of [reverse futility pruning].
///
/// [late move pruning]: https://www.chessprogramming.org/Late_Move_Reductions
fn lmp(&self, deficit: Score, draft: Depth) -> Option<Depth> {
/// [reverse futility pruning]: https://www.chessprogramming.org/Reverse_Futility_Pruning
fn rfp(&self, surplus: Score, draft: Depth) -> Option<Depth> {
match surplus.get() {
..0 => None,
0..680 => Some(draft - (surplus + 40) / 120),
680.. => Some(draft - 6),
}
}

/// An implementation of [futility pruning].
///
/// [futility pruning]: https://www.chessprogramming.org/Futility_Pruning
fn fp(&self, deficit: Score, draft: Depth) -> Option<Depth> {
let r = match deficit.get() {
..15 => return None,
15..50 => 1,
Expand All @@ -137,6 +137,13 @@ impl Engine {
Some(draft - r - draft / 4)
}

/// An implementation of [late move reductions].
///
/// [late move reductions]: https://www.chessprogramming.org/Late_Move_Reductions
fn lmr(&self, draft: Depth, idx: usize) -> i8 {
draft.get().max(1).ilog2() as i8 * idx.max(1).ilog2() as i8 / 3
}

/// The [alpha-beta] search.
///
/// [alpha-beta]: https://www.chessprogramming.org/Alpha-Beta
Expand Down Expand Up @@ -332,7 +339,7 @@ impl Engine {
return Ok(head >> tail);
}

let (head, tail) = self.driver.drive(head, tail, &moves, |score, m, gain| {
let (head, tail) = self.driver.drive(head, tail, &moves, |score, m, gain, n| {
let alpha = match score {
s if s >= beta => return Err(ControlFlow::Break),
s => s.max(alpha),
Expand All @@ -343,17 +350,24 @@ impl Engine {

self.tt.prefetch(next.zobrist());
if gain <= Value::lower() / 2 && !pos.is_check() && !next.is_check() {
if let Some(d) = self.lmp(alpha + next.evaluate(), draft) {
if let Some(d) = self.fp(alpha + next.evaluate(), draft) {
if d <= 0 || -self.nw::<0>(&next, -alpha, d + ply, ply + 1, ctrl)? <= alpha {
#[cfg(not(test))]
// The late move pruning heuristic is not exact.
// The futility pruning heuristic is not exact.
return Err(ControlFlow::Continue);
}
}
}

let partial = match -self.nw(&next, -alpha, depth, ply + 1, ctrl)? {
partial if partial <= alpha || partial >= beta => partial,
let lmr = match self.lmr(draft, n) {

Check warning on line 362 in lib/search/engine.rs

View check run for this annotation

Codecov / codecov/patch

lib/search/engine.rs#L362

Added line #L362 was not covered by tests
#[cfg(not(test))]
// The late move reduction heuristic is not exact.
r @ 1.. if !is_pv => r,
_ => 0,
};

let partial = match -self.nw(&next, -alpha, depth - lmr, ply + 1, ctrl)? {
partial if partial <= alpha || (partial >= beta && lmr <= 0) => partial,
_ => -self.ab(&next, -beta..-alpha, depth, ply + 1, ctrl)?,
};

Expand Down

0 comments on commit eeec246

Please sign in to comment.