use crate::branching::Brancher;
use crate::branching::BrancherEvent;
use crate::branching::SelectionContext;
#[cfg(doc)]
use crate::branching::branchers::alternating::AlternatingBrancher;
use crate::branching::branchers::alternating::AlternatingStrategy;
use crate::branching::branchers::alternating::BrancherToUse;
use crate::results::SolutionReference;
#[derive(Debug)]
pub struct UntilSolution<Strategy> {
strategy_before_solution: Strategy,
has_found_solution: bool,
}
impl<Strategy> UntilSolution<Strategy> {
pub fn new(strategy: Strategy) -> Self {
Self {
strategy_before_solution: strategy,
has_found_solution: false,
}
}
}
impl<Strategy: AlternatingStrategy> AlternatingStrategy for UntilSolution<Strategy> {
fn next_decision(&mut self, context: &mut SelectionContext) -> BrancherToUse {
if self.has_found_solution {
BrancherToUse::Default
} else {
self.strategy_before_solution.next_decision(context)
}
}
fn is_using_default_brancher(&self) -> bool {
self.has_found_solution || self.strategy_before_solution.is_using_default_brancher()
}
fn subscribe_to_events(&self) -> Vec<BrancherEvent> {
vec![BrancherEvent::Solution]
.into_iter()
.chain(self.strategy_before_solution.subscribe_to_events())
.collect()
}
fn on_solution(&mut self, _solution: SolutionReference) {
self.has_found_solution = true;
}
fn on_restart(&mut self) {
if !self.has_found_solution {
self.strategy_before_solution.on_restart();
}
}
fn is_restart_pointless(
&mut self,
default_brancher: &mut impl Brancher,
other_brancher: &mut impl Brancher,
) -> bool {
if self.has_found_solution {
default_brancher.is_restart_pointless()
} else {
self.strategy_before_solution
.is_restart_pointless(default_brancher, other_brancher)
}
}
fn will_always_use_default(&self) -> bool {
self.has_found_solution || self.strategy_before_solution.will_always_use_default()
}
}
#[cfg(test)]
mod tests {
use crate::Solver;
use crate::basic_types::tests::TestRandom;
use crate::branching::Brancher;
use crate::branching::SelectionContext;
use crate::branching::branchers::alternating::AlternatingBrancher;
use crate::branching::branchers::alternating::every_x_restarts::EveryXRestarts;
use crate::branching::branchers::alternating::other_only::OtherOnly;
use crate::branching::branchers::alternating::until_solution::UntilSolution;
use crate::engine::Assignments;
use crate::results::Solution;
use crate::results::SolutionReference;
#[test]
fn test_switch_to_default_after_first_solution() {
let solver = Solver::default();
let mut brancher = AlternatingBrancher::new(
&solver,
solver.default_brancher(),
UntilSolution::new(OtherOnly),
);
let assignments = Assignments::default();
let empty_solution_reference = SolutionReference::new(&assignments);
assert!(!brancher.is_using_default_brancher());
brancher.on_solution(empty_solution_reference);
assert!(brancher.is_using_default_brancher());
brancher.on_solution(empty_solution_reference);
assert!(brancher.is_using_default_brancher());
brancher.on_solution(empty_solution_reference);
assert!(brancher.is_using_default_brancher());
}
#[test]
fn test_switch_after_first_solution() {
let assignments = Assignments::default();
let solver = Solver::default();
let mut brancher = AlternatingBrancher::new(
&solver,
solver.default_brancher(),
UntilSolution::new(OtherOnly),
);
assert!(!brancher.is_using_default_brancher());
brancher.on_restart();
let _ = brancher.next_decision(&mut SelectionContext::new(
&assignments,
&mut TestRandom::default(),
));
assert!(!brancher.is_using_default_brancher());
brancher.on_restart();
let _ = brancher.next_decision(&mut SelectionContext::new(
&assignments,
&mut TestRandom::default(),
));
assert!(!brancher.is_using_default_brancher());
brancher.on_solution(Solution::from(assignments.clone()).as_reference());
let _ = brancher.next_decision(&mut SelectionContext::new(
&assignments,
&mut TestRandom::default(),
));
assert!(brancher.is_using_default_brancher());
brancher.on_restart();
let _ = brancher.next_decision(&mut SelectionContext::new(
&assignments,
&mut TestRandom::default(),
));
assert!(brancher.is_using_default_brancher());
brancher.on_restart();
let _ = brancher.next_decision(&mut SelectionContext::new(
&assignments,
&mut TestRandom::default(),
));
assert!(brancher.is_using_default_brancher());
brancher.on_solution(Solution::from(assignments.clone()).as_reference());
let _ = brancher.next_decision(&mut SelectionContext::new(
&assignments,
&mut TestRandom::default(),
));
assert!(brancher.is_using_default_brancher());
}
#[test]
fn test_every_restart_until_first_solution() {
let assignments = Assignments::default();
let solver = Solver::default();
let mut brancher = AlternatingBrancher::new(
&solver,
solver.default_brancher(),
UntilSolution::new(EveryXRestarts::new(1)),
);
assert!(!brancher.is_using_default_brancher());
brancher.on_restart();
let _ = brancher.next_decision(&mut SelectionContext::new(
&assignments,
&mut TestRandom::default(),
));
assert!(brancher.is_using_default_brancher());
brancher.on_restart();
let _ = brancher.next_decision(&mut SelectionContext::new(
&assignments,
&mut TestRandom::default(),
));
assert!(!brancher.is_using_default_brancher());
brancher.on_solution(Solution::from(assignments.clone()).as_reference());
let _ = brancher.next_decision(&mut SelectionContext::new(
&assignments,
&mut TestRandom::default(),
));
assert!(brancher.is_using_default_brancher());
brancher.on_restart();
let _ = brancher.next_decision(&mut SelectionContext::new(
&assignments,
&mut TestRandom::default(),
));
assert!(brancher.is_using_default_brancher());
brancher.on_restart();
let _ = brancher.next_decision(&mut SelectionContext::new(
&assignments,
&mut TestRandom::default(),
));
assert!(brancher.is_using_default_brancher());
brancher.on_solution(Solution::from(assignments.clone()).as_reference());
let _ = brancher.next_decision(&mut SelectionContext::new(
&assignments,
&mut TestRandom::default(),
));
assert!(brancher.is_using_default_brancher());
}
}