Skip to content

Commit

Permalink
further simplify futility pruning
Browse files Browse the repository at this point in the history
  • Loading branch information
brunocodutra committed Jan 24, 2025
1 parent 18b3d9e commit 7b1d0cd
Show file tree
Hide file tree
Showing 2 changed files with 13 additions and 29 deletions.
33 changes: 10 additions & 23 deletions lib/search/driver.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,10 @@
use crate::search::{Interrupted, Pv, Score, ThreadCount};
use crate::util::{Assume, Integer};
use crate::{chess::Move, nnue::Value};
use derive_more::From;
use rayon::{prelude::*, ThreadPool, ThreadPoolBuilder};
use std::cmp::max_by_key;
use std::sync::atomic::{AtomicI16, Ordering};

/// Whether the search should be [`Interrupted`] or exited early.
#[derive(Debug, Clone, Eq, PartialEq, Ord, PartialOrd, Hash, From)]
pub enum ControlFlow {
Interrupt(Interrupted),
Continue,
Break,
}

/// A parallel search driver.
#[derive(Debug)]
pub enum Driver {
Expand Down Expand Up @@ -43,16 +34,14 @@ impl Driver {
f: F,
) -> Result<(Move, Pv<N>), Interrupted>
where
F: Fn(Score, Move, Value, usize) -> Result<Pv<N>, ControlFlow> + Sync,
F: Fn(Score, Move, Value, usize) -> Result<Option<Pv<N>>, Interrupted> + Sync,
{
match self {
Self::Sequential => {
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),
Ok(partial) => {
match f(tail.score(), m, gain, idx)? {
None => break,
Some(partial) => {
if partial > tail {
(head, tail) = (m, partial)
}
Expand All @@ -71,17 +60,15 @@ impl Driver {
.rev()
.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) => {
match f(Score::new(score.load(Relaxed)), m, gain, idx)? {
None => Ok(None),
Some(partial) => {
score.fetch_max(partial.score().get(), Relaxed);
Some(Ok(Some((m, partial, usize::MAX - idx))))
Ok(Some((m, partial, usize::MAX - idx)))
}
}
})
.while_some()
.take_any_while(|x| matches!(x, Ok(Some(_))))
.chain([Ok(Some((head, tail, usize::MAX)))])
.try_reduce(
|| None,
Expand Down Expand Up @@ -115,7 +102,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(Some(Pv::new(v.saturate(), [])))),
Ok((head, tail))
)
}
Expand Down
9 changes: 3 additions & 6 deletions lib/search/engine.rs
Original file line number Diff line number Diff line change
Expand Up @@ -349,7 +349,7 @@ impl Engine {

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 if s >= beta => return Ok(None),
s => s.max(alpha),
};

Expand All @@ -362,10 +362,7 @@ impl Engine {
if self.fp(deficit, draft).is_some_and(|d| d <= 0) {
#[cfg(not(test))]
// The futility pruning heuristic is not exact.
return match draft.get() {
..3 => Err(ControlFlow::Break),
3.. => Err(ControlFlow::Continue),
};
return Ok(None);
}
}

Expand All @@ -381,7 +378,7 @@ impl Engine {
_ => -self.ab(&next, -beta..-alpha, depth, ply + 1, ctrl)?,
};

Ok(partial)
Ok(Some(partial))
})?;

self.record(pos, &moves, bounds, depth, ply, head, tail.score());
Expand Down

0 comments on commit 7b1d0cd

Please sign in to comment.