stalmarck_sat/core/
formula.rs1use std::collections::HashMap;
2
3#[derive(Debug, Clone, Default)]
5pub struct Formula {
6 clauses: Vec<Vec<i32>>,
7
8 implication_form: Option<ImplicationFormula>,
10
11 triplets: Option<TripletFormula>,
13 num_vars: usize,
14}
15
16#[derive(Debug, Clone, PartialEq)]
18pub enum ImplicationFormula {
19 Var(i32),
21
22 Not(Box<ImplicationFormula>),
24
25 Implies(Box<ImplicationFormula>, Box<ImplicationFormula>),
27
28 Const(bool),
30}
31
32#[derive(Debug, Clone, PartialEq, Eq, Hash)]
34pub enum TripletVar {
35 Var(i32),
37
38 Const(bool),
40}
41
42#[derive(Debug, Clone, PartialEq)]
44pub struct TripletFormula {
45 pub triplets: Vec<(TripletVar, TripletVar, TripletVar)>,
47
48 pub bridge_vars: std::collections::HashMap<TripletVar, usize>,
50
51 pub next_bridge_var: i32,
53
54 pub root_var: Option<TripletVar>,
56
57 pub max_original_var: i32,
59}
60
61impl Formula {
62 pub fn new() -> Self {
64 Self::default()
65 }
66
67 pub fn add_clause(&mut self, literals: Vec<i32>) {
69 for &lit in &literals {
71 let var = lit.abs() as usize;
72 if var > self.num_vars {
73 self.num_vars = var;
74 }
75 }
76 self.clauses.push(literals);
77 }
78
79 pub fn set_num_variables(&mut self, num_vars: usize) {
81 self.num_vars = num_vars;
82 }
83
84 pub fn reserve_clauses(&mut self, num_clauses: usize) {
86 self.clauses.reserve(num_clauses);
87 }
88
89 pub fn translate_to_implication_form(&mut self) {
91 if self.clauses.is_empty() {
92 self.implication_form = Some(ImplicationFormula::Not(Box::new(
94 ImplicationFormula::Const(true),
95 )));
96 return;
97 }
98
99 let clause_exprs: Vec<ImplicationFormula> = self
100 .clauses
101 .iter()
102 .map(|clause| self.clause_to_implication(clause))
103 .collect();
104
105 let mut result = clause_exprs[0].clone();
108
109 for clause_expr in clause_exprs.iter().skip(1) {
111 result = ImplicationFormula::Not(Box::new(ImplicationFormula::Implies(
113 Box::new(result),
114 Box::new(ImplicationFormula::Not(Box::new(clause_expr.clone()))),
115 )));
116 }
117
118 self.remove_nots(&mut result);
120
121 self.implication_form = Some(result);
122 }
123
124 fn clause_to_implication(&self, clause: &[i32]) -> ImplicationFormula {
126 if clause.is_empty() {
127 return ImplicationFormula::Not(Box::new(ImplicationFormula::Const(true)));
129 }
130
131 if clause.len() == 1 {
132 return ImplicationFormula::Var(clause[0]);
134 }
135
136 let mut expr = ImplicationFormula::Var(clause[0]);
140
141 for &lit in &clause[1..] {
143 expr = ImplicationFormula::Implies(
145 Box::new(ImplicationFormula::Not(Box::new(expr))),
146 Box::new(ImplicationFormula::Var(lit)),
147 );
148 }
149
150 expr
151 }
152
153 fn remove_nots(&self, formula: &mut ImplicationFormula) {
155 let original_node = std::mem::replace(formula, ImplicationFormula::Const(true));
157
158 match original_node {
159 ImplicationFormula::Not(mut sub_expr_box) => {
160 self.remove_nots(&mut *sub_expr_box);
162
163 *formula = ImplicationFormula::Implies(
165 sub_expr_box,
166 Box::new(ImplicationFormula::Const(false)),
167 );
168 }
169 ImplicationFormula::Implies(mut left_box, mut right_box) => {
170 self.remove_nots(&mut *left_box);
172 self.remove_nots(&mut *right_box);
173
174 *formula = ImplicationFormula::Implies(left_box, right_box);
176 }
177 ImplicationFormula::Var(id) => {
178 if id < 0 {
179 let positive_id = id.abs();
181 *formula = ImplicationFormula::Implies(
182 Box::new(ImplicationFormula::Var(positive_id)),
183 Box::new(ImplicationFormula::Const(false)),
184 );
185 } else {
189 *formula = ImplicationFormula::Var(id);
191 }
192 }
193 ImplicationFormula::Const(constant) => {
194 *formula = ImplicationFormula::Const(constant);
196 }
197 }
198 }
199
200 pub fn get_implication_form(&self) -> Option<&ImplicationFormula> {
202 self.implication_form.as_ref()
203 }
204
205 pub fn encode_formula_to_triplets(&mut self) {
207 let root_implication_node = match self.implication_form.as_ref() {
208 Some(form) => form,
209 None => {
210 self.triplets = None;
213 return;
214 }
215 };
216
217 let mut triplet_formula = TripletFormula {
219 triplets: Vec::new(),
220 bridge_vars: HashMap::new(),
221 next_bridge_var: self.num_vars as i32 + 1000,
222 root_var: None,
223 max_original_var: self.num_vars as i32,
224 };
225
226 let mut processed_results: HashMap<*const ImplicationFormula, TripletVar> = HashMap::new();
228
229 let mut traversal_stack: Vec<&ImplicationFormula> = Vec::new();
231
232 traversal_stack.push(root_implication_node);
234
235 while let Some(current_node) = traversal_stack.last().cloned() {
236 let current_node_ptr = current_node as *const ImplicationFormula;
237
238 if processed_results.contains_key(¤t_node_ptr)
240 && !matches!(current_node, ImplicationFormula::Implies(_, _))
241 {
242 traversal_stack.pop();
243 continue;
244 }
245
246 match current_node {
247 ImplicationFormula::Var(id) => {
248 traversal_stack.pop();
250 let result = TripletVar::Var(*id);
251 processed_results.insert(current_node_ptr, result);
252 }
253 ImplicationFormula::Const(value) => {
254 traversal_stack.pop();
256 let result = TripletVar::Const(*value);
257 processed_results.insert(current_node_ptr, result);
258 }
259 ImplicationFormula::Implies(left_expr, right_expr) => {
260 let left_child = &**left_expr;
261 let right_child = &**right_expr;
262
263 let left_child_ptr = left_child as *const ImplicationFormula;
264 let right_child_ptr = right_child as *const ImplicationFormula;
265
266 let left_processed = processed_results.contains_key(&left_child_ptr);
267 let right_processed = processed_results.contains_key(&right_child_ptr);
268
269 if left_processed && right_processed {
270 traversal_stack.pop();
272
273 let var_a = processed_results
274 .get(&left_child_ptr)
275 .expect("Left child should be processed")
276 .clone();
277
278 let var_b = processed_results
279 .get(&right_child_ptr)
280 .expect("Right child should be processed")
281 .clone();
282
283 let bridge_id = triplet_formula.next_bridge_var;
285 triplet_formula.next_bridge_var += 1;
286 let bridge_var = TripletVar::Var(bridge_id);
287
288 triplet_formula
290 .triplets
291 .push((bridge_var.clone(), var_a, var_b));
292 triplet_formula
293 .bridge_vars
294 .insert(bridge_var.clone(), triplet_formula.triplets.len() - 1);
295 processed_results.insert(current_node_ptr, bridge_var);
296 } else {
297 if !left_processed {
299 traversal_stack.push(left_child);
301 }
302
303 if !right_processed {
304 traversal_stack.push(right_child);
306 }
307
308 }
310 }
311 ImplicationFormula::Not(_) => {
312 unreachable!("Not nodes should have been removed in the implication form");
314 }
315 }
316 }
317
318 triplet_formula.root_var = processed_results
320 .get(&(root_implication_node as *const ImplicationFormula))
321 .cloned();
322
323 self.triplets = Some(triplet_formula);
324 }
325
326 pub fn get_triplets(&self) -> Option<&TripletFormula> {
328 self.triplets.as_ref()
329 }
330
331 pub fn num_variables(&self) -> usize {
333 self.num_vars
334 }
335
336 pub fn num_clauses(&self) -> usize {
338 self.clauses.len()
339 }
340
341 pub fn get_clauses(&self) -> &[Vec<i32>] {
343 &self.clauses
344 }
345}