use std::sync::{Arc, Mutex};
use crate::literal::Var;
pub trait BranchingHeuristic: Send + Sync {
fn select(&mut self, candidates: &[Var], scores: &[f64]) -> Option<Var>;
fn on_conflict_var(&mut self, _var: Var, _level: u32) {}
fn on_conflict_var_with_lbd(&mut self, var: Var, lbd: u32) {
self.on_conflict_var(var, lbd);
}
}
pub type BoxedBranchingHeuristic = Arc<Mutex<dyn BranchingHeuristic>>;
#[cfg(test)]
mod tests {
use super::*;
struct MinimalHeuristic;
impl BranchingHeuristic for MinimalHeuristic {
fn select(&mut self, candidates: &[Var], _scores: &[f64]) -> Option<Var> {
candidates.first().copied()
}
}
struct RecordingHeuristic {
recorded_levels: Vec<u32>,
}
impl BranchingHeuristic for RecordingHeuristic {
fn select(&mut self, candidates: &[Var], _scores: &[f64]) -> Option<Var> {
candidates.first().copied()
}
fn on_conflict_var(&mut self, _var: Var, level: u32) {
self.recorded_levels.push(level);
}
}
#[test]
fn test_default_on_conflict_var_is_noop() {
let mut h = MinimalHeuristic;
h.on_conflict_var(Var::new(0), 1);
h.on_conflict_var(Var::new(7), 0);
let candidates = [Var::new(3), Var::new(5)];
let chosen = h.select(&candidates, &[0.0, 0.0]);
assert_eq!(chosen, Some(Var::new(3)));
}
#[test]
fn test_default_on_conflict_var_with_lbd_delegates_to_on_conflict_var() {
let mut h = RecordingHeuristic {
recorded_levels: Vec::new(),
};
h.on_conflict_var_with_lbd(Var::new(1), 3);
h.on_conflict_var_with_lbd(Var::new(2), 5);
assert_eq!(
h.recorded_levels,
vec![3, 5],
"default on_conflict_var_with_lbd must forward lbd to on_conflict_var"
);
}
}