pumpkin_solver/branching/value_selection/
phase_saving.rsuse log::warn;
use super::ValueSelector;
use crate::basic_types::KeyedVec;
use crate::basic_types::StorageKey;
use crate::branching::SelectionContext;
use crate::engine::predicates::predicate::Predicate;
use crate::engine::variables::Literal;
use crate::engine::variables::PropositionalVariable;
use crate::pumpkin_assert_moderate;
#[derive(Debug)]
pub struct PhaseSaving<Var, Value: PartialEq> {
saved_values: KeyedVec<Var, StoredValue<Value>>,
default_value: Value,
}
#[derive(Debug, Clone, PartialEq)]
enum StoredValue<Value: PartialEq> {
Frozen(Value),
Regular(Value),
}
impl<Value: Copy + PartialEq> StoredValue<Value> {
fn get_value(&self) -> Value {
match self {
StoredValue::Frozen(value) => *value,
StoredValue::Regular(value) => *value,
}
}
}
impl PhaseSaving<PropositionalVariable, bool> {
pub fn new(variables: &[PropositionalVariable]) -> Self {
if variables.is_empty() {
warn!("Empty set of variables provided to phase saving value selector, this could indicate an error")
}
PhaseSaving::with_default_value(variables, false)
}
}
impl<Var: StorageKey + Copy + PartialEq, Value: Copy + PartialEq> PhaseSaving<Var, Value> {
pub fn with_default_value(variables: &[Var], default_value: Value) -> Self {
PhaseSaving::with_initial_values(variables, vec![], default_value)
}
pub fn with_initial_values(
variables: &[Var],
variables_with_initial_value: Vec<(Var, Value)>,
default_value: Value,
) -> Self {
if variables.is_empty() {
warn!("Empty set of variables provided to phase saving value selector, this could indicate an error");
return PhaseSaving {
saved_values: KeyedVec::default(),
default_value,
};
}
pumpkin_assert_moderate!(
variables_with_initial_value
.iter()
.all(|(variable, _)| variables.contains(variable)),
"Not every variable in the provided values was in variables"
);
let max_index = variables
.iter()
.map(|variable| variable.index())
.max()
.unwrap();
let saved_values = KeyedVec::new(vec![StoredValue::Regular(default_value); max_index + 1]);
if max_index > 0 {
let mut phase_saving = PhaseSaving {
saved_values,
default_value,
};
for (var, value) in variables_with_initial_value {
phase_saving.freeze(var, value)
}
return phase_saving;
}
PhaseSaving {
saved_values,
default_value,
}
}
fn update(&mut self, variable: Var, new_value: Value) {
match self.saved_values[variable] {
StoredValue::Frozen(_) => {}
StoredValue::Regular(_) => {
self.saved_values[variable] = StoredValue::Regular(new_value);
}
}
}
pub fn freeze(&mut self, variable: Var, new_value: Value) {
self.saved_values[variable] = StoredValue::Frozen(new_value)
}
}
impl ValueSelector<PropositionalVariable> for PhaseSaving<PropositionalVariable, bool> {
fn select_value(
&mut self,
_: &mut SelectionContext,
decision_variable: PropositionalVariable,
) -> Predicate {
self.saved_values
.accomodate(decision_variable, StoredValue::Regular(self.default_value));
Literal::new(
decision_variable,
self.saved_values[decision_variable].get_value(),
)
.into()
}
fn on_unassign_literal(&mut self, lit: Literal) {
self.saved_values.accomodate(
lit.get_propositional_variable(),
StoredValue::Regular(self.default_value),
);
self.update(lit.get_propositional_variable(), lit.is_positive())
}
fn is_restart_pointless(&mut self) -> bool {
false
}
}
#[cfg(test)]
mod tests {
use super::PhaseSaving;
use crate::basic_types::tests::TestRandom;
use crate::basic_types::StorageKey;
use crate::branching::value_selection::phase_saving::StoredValue;
use crate::branching::value_selection::ValueSelector;
use crate::branching::SelectionContext;
use crate::engine::predicates::predicate::Predicate;
use crate::variables::Literal;
use crate::variables::PropositionalVariable;
#[test]
fn saved_value_is_returned_prop() {
let (assignments_integer, assignments_propositional) =
SelectionContext::create_for_testing(0, 1, None);
let mut test_rng = TestRandom::default();
let mut context = SelectionContext::new(
&assignments_integer,
&assignments_propositional,
&mut test_rng,
);
let propositional_variables = context.get_propositional_variables().collect::<Vec<_>>();
let mut phase_saving = PhaseSaving::new(&propositional_variables);
phase_saving.update(propositional_variables[0], true);
let chosen = phase_saving.select_value(&mut context, propositional_variables[0]);
if let Predicate::Literal(chosen) = chosen {
assert!(chosen.is_positive())
} else {
panic!("Predicate which was not a literal was returned")
}
}
#[test]
fn does_not_panic_with_unknown_variable_unassign() {
let mut phase_saving = PhaseSaving::new(&[]);
let literal = Literal::new(PropositionalVariable::create_from_index(1), false);
phase_saving.on_unassign_literal(literal);
assert_eq!(
phase_saving.saved_values[literal.get_propositional_variable()],
StoredValue::Regular(false)
);
}
#[test]
fn does_not_panic_with_unknown_selected_variable() {
let mut phase_saving = PhaseSaving::new(&[]);
let (assignments_integer, assignments_propositional) =
SelectionContext::create_for_testing(0, 0, None);
let mut test_rng = TestRandom::default();
let mut context = SelectionContext::new(
&assignments_integer,
&assignments_propositional,
&mut test_rng,
);
let variable = PropositionalVariable::create_from_index(1);
let selected = phase_saving.select_value(&mut context, variable);
assert_eq!(selected, Predicate::Literal(Literal::new(variable, false)));
}
}