1pub mod solve;
9
10use crate::adjacency::Adjacency;
11use crate::config::{Csp, SolveStats};
12use crate::constraint::{
13 self, AllDifferent, Constraint, ConstraintEnum, NotEqual, SoftLambdaConstraint, VarId,
14};
15use crate::domain::Domain;
16use crate::variable::Variable;
17
18impl<D: Domain> Csp<D> {
19 pub fn new() -> Self {
21 Self {
22 variables: Vec::new(),
23 constraints: Vec::new(),
24 adjacency: None,
25 stats: SolveStats::default(),
26 constraint_weights: Vec::new(),
27 var_constraint_ids: Vec::new(),
28 }
29 }
30
31 pub fn add_variable(&mut self, domain: D) -> VarId {
33 let id = self.variables.len() as VarId;
34 self.variables.push(Variable::new(domain));
35 id
36 }
37
38 pub fn add_variables(&mut self, domain: &D, count: usize) -> Vec<VarId> {
40 (0..count)
41 .map(|_| self.add_variable(domain.clone()))
42 .collect()
43 }
44
45 pub fn add_constraint(&mut self, c: impl Constraint<D> + 'static) {
47 self.constraints.push(ConstraintEnum::Custom(Box::new(c)));
48 }
49
50 pub fn add_constraint_enum(&mut self, c: ConstraintEnum<D>) {
52 self.constraints.push(c);
53 }
54
55 pub fn add_soft_constraint(&mut self, c: SoftLambdaConstraint<D>) {
57 self.constraints.push(ConstraintEnum::Soft(c));
58 }
59
60 pub fn add_not_equal(&mut self, x: VarId, y: VarId) {
62 self.constraints
63 .push(ConstraintEnum::NotEqual(NotEqual::new(x, y)));
64 }
65
66 pub fn add_all_different(&mut self, vars: Vec<VarId>) {
68 self.constraints
69 .push(ConstraintEnum::AllDifferent(AllDifferent::new(vars)));
70 }
71
72 pub fn add_equals(&mut self, var: VarId, value: D::Value)
74 where
75 D: 'static,
76 D::Value: Send + Sync,
77 {
78 self.add_constraint(constraint::LambdaConstraint::new(
79 vec![var],
80 move |assignment| match &assignment[var as usize] {
81 Some(v) => *v == value,
82 None => true,
83 },
84 format!("equals({var})"),
85 ));
86 }
87
88 pub fn add_less_than(&mut self, x: VarId, y: VarId)
90 where
91 D: 'static,
92 D::Value: PartialOrd + Send + Sync,
93 {
94 self.add_constraint(constraint::LambdaConstraint::new(
95 vec![x, y],
96 move |assignment| match (&assignment[x as usize], &assignment[y as usize]) {
97 (Some(a), Some(b)) => a < b,
98 _ => true,
99 },
100 format!("less_than({x},{y})"),
101 ));
102 }
103
104 pub fn add_greater_than(&mut self, x: VarId, y: VarId)
106 where
107 D: 'static,
108 D::Value: PartialOrd + Send + Sync,
109 {
110 self.add_constraint(constraint::LambdaConstraint::new(
111 vec![x, y],
112 move |assignment| match (&assignment[x as usize], &assignment[y as usize]) {
113 (Some(a), Some(b)) => a > b,
114 _ => true,
115 },
116 format!("greater_than({x},{y})"),
117 ));
118 }
119
120 pub fn finalize(&mut self)
123 where
124 D::Value: PartialEq + 'static,
125 {
126 let num_vars = self.variables.len();
127 self.adjacency = Some(Adjacency::build(num_vars, &self.constraints));
128
129 self.constraint_weights = vec![1.0; self.constraints.len()];
130 self.var_constraint_ids = vec![Vec::new(); num_vars];
131 for (ci, c) in self.constraints.iter().enumerate() {
132 for &v in c.scope() {
133 self.var_constraint_ids[v as usize].push(ci);
134 }
135 }
136 }
137}