use crate::basic_types::PredicateId;
use crate::basic_types::PredicateIdGenerator;
use crate::basic_types::Trail;
use crate::containers::KeyedVec;
use crate::containers::StorageKey;
use crate::engine::Assignments;
#[cfg(doc)]
use crate::predicates::Predicate;
use crate::pumpkin_assert_extreme;
#[derive(Clone, Debug, Default)]
pub(crate) struct PredicateIdAssignments {
trail: Trail<PredicateId>,
predicate_values: KeyedVec<PredicateId, PredicateValue>,
satisfied_predicates: Vec<PredicateId>,
}
#[derive(Clone, Copy, Debug, PartialEq)]
pub(crate) enum PredicateValue {
AssignedTrue,
AssignedFalse,
Unknown,
}
impl PredicateValue {
fn is_satisified(&self) -> bool {
matches!(self, PredicateValue::AssignedTrue)
}
fn is_falsified(&self) -> bool {
matches!(self, PredicateValue::AssignedFalse)
}
fn is_unknown(&self) -> bool {
matches!(self, PredicateValue::Unknown)
}
}
impl PredicateIdAssignments {
fn predicate_ids(&self) -> impl Iterator<Item = PredicateId> + '_ {
self.predicate_values.keys()
}
pub(crate) fn drain_satisfied_predicates(&mut self) -> impl Iterator<Item = PredicateId> + '_ {
self.satisfied_predicates.drain(..)
}
pub(crate) fn new_checkpoint(&mut self) {
self.trail.new_checkpoint()
}
pub(crate) fn store_predicate(&mut self, predicate_id: PredicateId, value: PredicateValue) {
self.predicate_values
.accomodate(predicate_id, PredicateValue::Unknown);
pumpkin_assert_extreme!(
self.predicate_values[predicate_id] == PredicateValue::Unknown
|| self.predicate_values[predicate_id] == value,
"Expected {:?} to be either unknown/untracked or for it to equal {value:?} for {predicate_id:?}",
self.predicate_values[predicate_id]
);
if self.predicate_values[predicate_id] != value {
if value == PredicateValue::AssignedTrue {
self.satisfied_predicates.push(predicate_id)
}
self.predicate_values[predicate_id] = value;
self.trail.push(predicate_id)
}
}
fn update_if_unknown(
&mut self,
predicate_id: PredicateId,
assignments: &Assignments,
predicate_id_generator: &mut PredicateIdGenerator,
) {
if predicate_id.index() >= self.predicate_values.len() {
self.predicate_values
.resize(predicate_id.index() + 1, PredicateValue::Unknown);
}
if self.predicate_values[predicate_id].is_unknown() {
let predicate = predicate_id_generator.get_predicate(predicate_id);
let value = match assignments.evaluate_predicate(predicate) {
Some(satisfied) => {
if satisfied {
PredicateValue::AssignedTrue
} else {
PredicateValue::AssignedFalse
}
}
None => PredicateValue::Unknown,
};
self.store_predicate(predicate_id, value);
}
}
pub(crate) fn is_satisfied(
&mut self,
predicate_id: PredicateId,
assignments: &Assignments,
predicate_id_generator: &mut PredicateIdGenerator,
) -> bool {
self.update_if_unknown(predicate_id, assignments, predicate_id_generator);
self.predicate_values[predicate_id].is_satisified()
}
pub(crate) fn is_falsified(
&mut self,
predicate_id: PredicateId,
assignments: &Assignments,
predicate_id_generator: &mut PredicateIdGenerator,
) -> bool {
self.update_if_unknown(predicate_id, assignments, predicate_id_generator);
self.predicate_values[predicate_id].is_falsified()
}
pub(crate) fn synchronise(&mut self, new_checkpoint: usize) {
self.satisfied_predicates.clear();
self.trail
.synchronise(new_checkpoint)
.for_each(|predicate_id| {
self.predicate_values[predicate_id] = PredicateValue::Unknown
})
}
pub(crate) fn is_unknown(&self, predicate_id: PredicateId) -> bool {
predicate_id.index() >= self.predicate_values.len()
|| self.predicate_values[predicate_id].is_unknown()
}
pub(crate) fn debug_empty_clone(&self) -> Self {
let mut predicate_id_assignments = PredicateIdAssignments::default();
for predicate_id in self.predicate_ids() {
predicate_id_assignments.store_predicate(predicate_id, PredicateValue::Unknown);
}
predicate_id_assignments
}
pub(crate) fn debug_create_from_assignments(
&mut self,
assignments: &Assignments,
predicate_to_id: &mut PredicateIdGenerator,
) {
self.predicate_ids()
.collect::<Vec<_>>()
.into_iter()
.for_each(|predicate_id| {
let predicate = predicate_to_id.get_predicate(predicate_id);
let value = if self.is_unknown(predicate_id) {
PredicateValue::Unknown
} else {
match assignments.evaluate_predicate(predicate) {
Some(assigned) => {
if assigned {
PredicateValue::AssignedTrue
} else {
PredicateValue::AssignedFalse
}
}
None => PredicateValue::Unknown,
}
};
self.store_predicate(predicate_id, value);
});
}
}