use crate::{PropagatorId, VariableId};
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum BoundKind {
Below,
Above,
}
#[derive(Clone, Debug, PartialEq, Eq)]
pub enum ChangeReason {
Branch { variable: VariableId, value: i32 },
Propagator {
propagator: PropagatorId,
variable: VariableId,
removed_value: Option<i32>,
bound: Option<(BoundKind, i32)>,
},
PropagatorConflict {
literals: Vec<(VariableId, i32)>,
},
}
#[derive(Clone, Debug, Default, PartialEq, Eq)]
pub struct Explanation {
entries: Vec<ChangeReason>,
}
impl Explanation {
#[must_use]
pub fn new() -> Self {
Self {
entries: Vec::new(),
}
}
#[must_use]
pub fn entries(&self) -> &[ChangeReason] {
&self.entries
}
pub fn record(&mut self, reason: ChangeReason) {
self.entries.push(reason);
}
pub fn reset(&mut self) {
self.entries.clear();
}
pub fn truncate(&mut self, len: usize) {
self.entries.truncate(len);
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::VariableId;
use slotmap::SlotMap;
fn make_var() -> VariableId {
let mut sm: SlotMap<crate::VariableKey, ()> = SlotMap::with_key();
VariableId::from_key(sm.insert(()))
}
#[test]
fn records_and_resets_entries() {
let mut explanation = Explanation::new();
assert!(explanation.entries().is_empty());
explanation.record(ChangeReason::Branch {
variable: make_var(),
value: 1,
});
assert_eq!(explanation.entries().len(), 1);
explanation.reset();
assert!(explanation.entries().is_empty());
}
#[test]
fn truncates_to_prefix() {
let mut explanation = Explanation::new();
for value in 1..=3 {
explanation.record(ChangeReason::Branch {
variable: make_var(),
value,
});
}
explanation.truncate(2);
assert_eq!(explanation.entries().len(), 2);
}
}