use crate::constraints::props::PropId;
use crate::search::Space;
use crate::variables::{VarId, Val};
pub fn split_on_unassigned(mut space: Space) -> SplitOnUnassigned {
if let Some(pivot) = space.vars.get_unassigned_var() {
let mid = space.vars[pivot].mid();
let checkpoint = space.trail.push_checkpoint();
SplitOnUnassigned {
branch: Some(BranchState::BinarySplit {
space,
checkpoint,
pivot,
mid,
is_left: true
}),
}
} else {
SplitOnUnassigned { branch: None }
}
}
#[derive(Debug)]
pub struct SplitOnUnassigned {
branch: Option<BranchState>,
}
#[derive(Debug)]
enum BranchState {
BinarySplit {
space: Space,
checkpoint: usize, pivot: VarId,
mid: Val,
is_left: bool,
},
}
impl SplitOnUnassigned {
pub fn get_propagation_count(&self) -> usize {
match &self.branch {
Some(BranchState::BinarySplit { space, .. }) => space.get_propagation_count(),
None => 0,
}
}
pub fn get_node_count(&self) -> usize {
match &self.branch {
Some(BranchState::BinarySplit { space, .. }) => space.get_node_count(),
None => 0,
}
}
}
impl Iterator for SplitOnUnassigned {
type Item = (Space, PropId);
fn next(&mut self) -> Option<Self::Item> {
let branch_state = self.branch.take()?;
match branch_state {
BranchState::BinarySplit { mut space, checkpoint, pivot, mid, is_left } => {
space.props.increment_node_count();
if is_left {
self.branch = Some(BranchState::BinarySplit {
space: space.clone(),
checkpoint,
pivot,
mid,
is_left: false
});
let p = space.props.less_than_or_equals(pivot, mid);
Some((space, p))
} else {
Self::backtrack_to_checkpoint(&mut space, checkpoint);
let p = space.props.greater_than(pivot, mid);
Some((space, p))
}
}
}
}
}
impl SplitOnUnassigned {
fn backtrack_to_checkpoint(space: &mut Space, _checkpoint: usize) {
use crate::search::trail::VarTrail;
if let Some(changes) = space.trail.pop_checkpoint() {
for entry in changes {
space.vars[entry.var_id].restore_snapshot(&entry.old_state);
}
}
}
}