use std::fmt::Debug;
use crate::domain::Domain;
use crate::variable::Variable;
pub type VarId = u32;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum Revision {
Unchanged,
Changed,
Unsatisfiable,
}
pub trait Constraint<D: Domain>: Debug {
fn scope(&self) -> &[VarId];
fn check(&self, assignment: &[Option<D::Value>]) -> bool;
fn revise(&self, vars: &mut [Variable<D>], depth: usize) -> Revision {
let scope = self.scope();
if scope.len() != 2 {
return Revision::Unchanged;
}
let xi = scope[0] as usize;
let xj = scope[1] as usize;
let mut changed = false;
let mut assignment: Vec<Option<D::Value>> = vec![None; vars.len()];
let vals_i = vars[xi].domain.values();
let vals_j = vars[xj].domain.values();
for vi in &vals_i {
let mut supported = false;
assignment[xi] = Some(vi.clone());
for vj in &vals_j {
assignment[xj] = Some(vj.clone());
if self.check(&assignment) {
supported = true;
break;
}
}
if !supported {
vars[xi].prune(vi, depth);
changed = true;
}
}
assignment[xi] = None;
assignment[xj] = None;
if vars[xi].domain.is_empty() {
return Revision::Unsatisfiable;
}
let vals_j = vars[xj].domain.values();
let vals_i = vars[xi].domain.values();
for vj in &vals_j {
let mut supported = false;
assignment[xj] = Some(vj.clone());
for vi in &vals_i {
assignment[xi] = Some(vi.clone());
if self.check(&assignment) {
supported = true;
break;
}
}
if !supported {
vars[xj].prune(vj, depth);
changed = true;
}
}
if vars[xj].domain.is_empty() {
return Revision::Unsatisfiable;
}
if changed { Revision::Changed } else { Revision::Unchanged }
}
}
pub trait SoftConstraint<D: Domain>: Constraint<D> {
fn penalty(&self) -> f64;
}