pumpkin_core/constraints/
table.rs1use std::collections::BTreeMap;
2
3use super::Constraint;
4use super::NegatableConstraint;
5use crate::predicate;
6use crate::proof::ConstraintTag;
7use crate::variables::IntegerVariable;
8use crate::variables::Literal;
9use crate::ConstraintOperationError;
10use crate::Solver;
11
12pub fn table<Var: IntegerVariable + 'static>(
24 xs: impl IntoIterator<Item = Var>,
25 table: Vec<Vec<i32>>,
26 constraint_tag: ConstraintTag,
27) -> impl NegatableConstraint {
28 Table {
29 xs: xs.into_iter().collect(),
30 table,
31 constraint_tag,
32 }
33}
34
35pub fn negative_table<Var: IntegerVariable + 'static>(
47 xs: impl IntoIterator<Item = Var>,
48 table: Vec<Vec<i32>>,
49 constraint_tag: ConstraintTag,
50) -> impl NegatableConstraint {
51 NegativeTable {
52 xs: xs.into_iter().collect(),
53 table,
54 constraint_tag,
55 }
56}
57
58struct Table<Var> {
59 xs: Vec<Var>,
60 table: Vec<Vec<i32>>,
61 constraint_tag: ConstraintTag,
62}
63
64impl<Var: IntegerVariable> Table<Var> {
65 fn encode(
66 self,
67 solver: &mut Solver,
68 reification_literal: Option<Literal>,
69 ) -> Result<(), ConstraintOperationError> {
70 let ys: Vec<_> = (0..self.table.len())
72 .map(|_| solver.new_literal())
73 .collect();
74
75 for (col, x_col) in self.xs.iter().enumerate() {
77 let mut values = BTreeMap::new();
79
80 for (row, &y_row) in ys.iter().enumerate() {
82 let value = self.table[row][col];
83
84 let supports = values.entry(value).or_insert(vec![]);
85 supports.push(y_row);
86 }
87
88 for (value, supports) in values {
91 let condition = predicate![x_col == value];
92
93 for support in supports.iter() {
95 let mut clause = vec![support.get_false_predicate(), condition];
96
97 clause.extend(reification_literal.iter().map(|l| l.get_false_predicate()));
100
101 solver.add_clause(clause, self.constraint_tag)?;
102 }
103
104 let mut clause = vec![!condition];
106 clause.extend(supports.iter().map(|l| l.get_true_predicate()));
107 clause.extend(reification_literal.iter().map(|l| l.get_false_predicate()));
109 }
110 }
111
112 let poster = solver.add_constraint(crate::constraints::clause(ys, self.constraint_tag));
114 if let Some(literal) = reification_literal {
115 poster.implied_by(literal)?;
116 } else {
117 poster.post()?;
118 }
119
120 Ok(())
121 }
122}
123
124impl<Var: IntegerVariable> Constraint for Table<Var> {
125 fn post(self, solver: &mut Solver) -> Result<(), ConstraintOperationError> {
126 self.encode(solver, None)
127 }
128
129 fn implied_by(
130 self,
131 solver: &mut Solver,
132 reification_literal: Literal,
133 ) -> Result<(), ConstraintOperationError> {
134 self.encode(solver, Some(reification_literal))
135 }
136}
137
138impl<Var: IntegerVariable + 'static> NegatableConstraint for Table<Var> {
139 type NegatedConstraint = NegativeTable<Var>;
140
141 fn negation(&self) -> Self::NegatedConstraint {
142 let xs = self.xs.clone();
143 let table = self.table.clone();
144 let constraint_tag = self.constraint_tag;
145
146 NegativeTable {
147 xs,
148 table,
149 constraint_tag,
150 }
151 }
152}
153
154struct NegativeTable<Var> {
155 xs: Vec<Var>,
156 table: Vec<Vec<i32>>,
157 constraint_tag: ConstraintTag,
158}
159
160impl<Var: IntegerVariable> Constraint for NegativeTable<Var> {
161 fn post(self, solver: &mut Solver) -> Result<(), ConstraintOperationError> {
162 for row in self.table {
163 let clause: Vec<_> = self
164 .xs
165 .iter()
166 .zip(row)
167 .map(|(x, value)| predicate![x != value])
168 .collect();
169
170 solver.add_clause(clause, self.constraint_tag)?;
171 }
172
173 Ok(())
174 }
175
176 fn implied_by(
177 self,
178 solver: &mut Solver,
179 reification_literal: Literal,
180 ) -> Result<(), ConstraintOperationError> {
181 for row in self.table {
182 let clause: Vec<_> = self
183 .xs
184 .iter()
185 .zip(row)
186 .map(|(x, value)| predicate![x != value])
187 .chain(std::iter::once(reification_literal.get_false_predicate()))
188 .collect();
189
190 solver.add_clause(clause, self.constraint_tag)?;
191 }
192
193 Ok(())
194 }
195}
196
197impl<Var: IntegerVariable + 'static> NegatableConstraint for NegativeTable<Var> {
198 type NegatedConstraint = Table<Var>;
199
200 fn negation(&self) -> Self::NegatedConstraint {
201 let xs = self.xs.clone();
202 let table = self.table.clone();
203 let constraint_tag = self.constraint_tag;
204
205 Table {
206 xs,
207 table,
208 constraint_tag,
209 }
210 }
211}