use std::collections::HashMap;
use unifier::VariableId;
use unifier::constraint::{AtLeast, AtMost, Constraint, ExactlyOne};
fn vars(count: usize) -> Vec<VariableId> {
(0..count).map(|index| VariableId(index as u32)).collect()
}
fn assign(pairs: &[(VariableId, i64)]) -> HashMap<VariableId, i64> {
pairs.iter().copied().collect()
}
#[test]
fn exactly_one_waits_for_the_group_instead_of_crying_early() {
let scope = vars(3);
let constraint = ExactlyOne::new(scope.clone(), 1);
assert!(constraint.is_satisfied(&assign(&[])));
assert!(constraint.is_satisfied(&assign(&[(scope[0], 0)])));
assert!(constraint.is_satisfied(&assign(&[(scope[0], 1)])));
assert!(!constraint.is_satisfied(&assign(&[(scope[0], 1), (scope[1], 1)])));
assert!(!constraint.is_satisfied(&assign(&[(scope[0], 0), (scope[1], 0), (scope[2], 0)])));
assert!(constraint.is_satisfied(&assign(&[(scope[0], 0), (scope[1], 1), (scope[2], 0)])));
}
#[test]
fn at_least_waits_until_the_count_is_out_of_reach() {
let scope = vars(3);
let constraint = AtLeast::new(2, scope.clone(), 1);
assert!(constraint.is_satisfied(&assign(&[])));
assert!(constraint.is_satisfied(&assign(&[(scope[0], 0)])));
assert!(!constraint.is_satisfied(&assign(&[(scope[0], 0), (scope[1], 0)])));
assert!(constraint.is_satisfied(&assign(&[(scope[0], 1), (scope[1], 1), (scope[2], 0)])));
assert!(!constraint.is_satisfied(&assign(&[(scope[0], 1), (scope[1], 0), (scope[2], 0)])));
}
#[test]
fn at_most_already_kept_the_contract() {
let scope = vars(3);
let constraint = AtMost::new(1, scope.clone(), 1);
assert!(constraint.is_satisfied(&assign(&[])));
assert!(constraint.is_satisfied(&assign(&[(scope[0], 1)])));
assert!(!constraint.is_satisfied(&assign(&[(scope[0], 1), (scope[1], 1)])));
}
#[test]
fn the_count_agrees_with_satisfaction_under_partial_assignments() {
let scope = vars(3);
let cases: Vec<Box<dyn Constraint>> = vec![
Box::new(ExactlyOne::new(scope.clone(), 1)),
Box::new(AtLeast::new(2, scope.clone(), 1)),
Box::new(AtMost::new(1, scope.clone(), 1)),
];
for constraint in &cases {
for a in [None, Some(0), Some(1)] {
for b in [None, Some(0), Some(1)] {
for c in [None, Some(0), Some(1)] {
let mut assignment = HashMap::new();
for (var, value) in scope.iter().zip([a, b, c]) {
if let Some(value) = value {
assignment.insert(*var, value);
}
}
assert_eq!(
constraint.violations(&assignment) == 0,
constraint.is_satisfied(&assignment),
"{}: {assignment:?}",
constraint.name(),
);
}
}
}
}
}