use crate::internal::id::{ClauseId, VariableId};
use crate::solver::{decision::Decision, decision_map::DecisionMap};
#[derive(Default)]
pub(crate) struct DecisionTracker {
map: DecisionMap,
stack: Vec<Decision>,
propagate_index: usize,
}
impl DecisionTracker {
pub(crate) fn clear(&mut self) {
*self = Default::default();
}
#[cfg(feature = "diagnostics")]
pub(crate) fn len(&self) -> usize {
self.map.len()
}
#[inline(always)]
pub(crate) fn assigned_value(&self, variable_id: VariableId) -> Option<bool> {
self.map.value(variable_id)
}
pub(crate) fn map(&self) -> &DecisionMap {
&self.map
}
pub(crate) fn stack(&self) -> impl DoubleEndedIterator<Item = Decision> + '_ {
self.stack.iter().copied()
}
pub(crate) fn level(&self, variable_id: VariableId) -> u32 {
self.map.level(variable_id)
}
pub(crate) fn find_clause_for_assignment(&self, variable_id: VariableId) -> Option<ClauseId> {
self.stack
.iter()
.find(|d| d.variable == variable_id)
.map(|d| d.derived_from)
}
pub(crate) fn try_add_decision(&mut self, decision: Decision, level: u32) -> Result<bool, ()> {
match self.map.value(decision.variable) {
None => {
self.map.set(decision.variable, decision.value, level);
self.stack.push(decision);
Ok(true)
}
Some(value) if value == decision.value => Ok(false),
_ => Err(()),
}
}
pub(crate) fn undo_until(&mut self, level: u32) {
if level == 0 {
self.clear();
return;
}
while let Some(decision) = self.stack.last() {
if self.level(decision.variable) <= level {
break;
}
self.undo_last();
}
}
pub(crate) fn undo_last(&mut self) -> (Decision, u32) {
let decision = self.stack.pop().unwrap();
self.map.reset(decision.variable);
self.propagate_index = self.stack.len();
let top_decision = self.stack.last().unwrap();
(decision, self.map.level(top_decision.variable))
}
pub(crate) fn next_unpropagated(&mut self) -> Option<Decision> {
let &decision = self.stack[self.propagate_index..].iter().next()?;
self.propagate_index += 1;
Some(decision)
}
}