csp_solver/constraint/
traits.rs1use std::fmt::Debug;
4
5use crate::domain::Domain;
6use crate::variable::Variable;
7
8pub type VarId = u32;
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
13pub enum Revision {
14 Unchanged,
15 Changed,
16 Unsatisfiable,
17}
18
19pub trait Constraint<D: Domain>: Debug {
21 fn scope(&self) -> &[VarId];
23
24 fn check(&self, assignment: &[Option<D::Value>]) -> bool;
26
27 fn revise(&self, vars: &mut [Variable<D>], depth: usize) -> Revision {
29 let scope = self.scope();
30 if scope.len() != 2 {
31 return Revision::Unchanged;
32 }
33
34 let xi = scope[0] as usize;
35 let xj = scope[1] as usize;
36 let mut changed = false;
37
38 let mut assignment: Vec<Option<D::Value>> = vec![None; vars.len()];
39
40 let vals_i = vars[xi].domain.values();
41 let vals_j = vars[xj].domain.values();
42
43 for vi in &vals_i {
44 let mut supported = false;
45 assignment[xi] = Some(vi.clone());
46 for vj in &vals_j {
47 assignment[xj] = Some(vj.clone());
48 if self.check(&assignment) {
49 supported = true;
50 break;
51 }
52 }
53 if !supported {
54 vars[xi].prune(vi, depth);
55 changed = true;
56 }
57 }
58 assignment[xi] = None;
59 assignment[xj] = None;
60
61 if vars[xi].domain.is_empty() {
62 return Revision::Unsatisfiable;
63 }
64
65 let vals_j = vars[xj].domain.values();
66 let vals_i = vars[xi].domain.values();
67
68 for vj in &vals_j {
69 let mut supported = false;
70 assignment[xj] = Some(vj.clone());
71 for vi in &vals_i {
72 assignment[xi] = Some(vi.clone());
73 if self.check(&assignment) {
74 supported = true;
75 break;
76 }
77 }
78 if !supported {
79 vars[xj].prune(vj, depth);
80 changed = true;
81 }
82 }
83
84 if vars[xj].domain.is_empty() {
85 return Revision::Unsatisfiable;
86 }
87
88 if changed { Revision::Changed } else { Revision::Unchanged }
89 }
90}
91
92pub trait SoftConstraint<D: Domain>: Constraint<D> {
98 fn penalty(&self) -> f64;
100}