1#![warn(clippy::all, clippy::pedantic, clippy::nursery, clippy::cargo)]
2#![allow(unsafe_code, clippy::cast_possible_truncation, clippy::cast_sign_loss)]
15
16use super::clause::Clause;
17use super::expr::{Expr, apply_laws};
18use crate::sat::clause_storage::LiteralStorage;
19use crate::sat::literal;
20use crate::sat::literal::{Literal, PackedLiteral, Variable};
21use crate::sat::solver::Solutions;
22use itertools::Itertools;
23use smallvec::SmallVec;
24use std::fmt::Display;
25use std::num::NonZeroI32;
26use std::ops::{Index, IndexMut};
27
28pub type DecisionLevel = usize;
30
31#[derive(Debug, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Default)]
41pub struct Cnf<L: Literal = PackedLiteral, S: LiteralStorage<L> = SmallVec<[L; 8]>> {
42 pub clauses: Vec<Clause<L, S>>,
44 pub num_vars: usize,
49 pub vars: Vec<Variable>,
51 pub lits: Vec<L>,
53 pub non_learnt_idx: usize,
58}
59
60impl<T: Literal, S: LiteralStorage<T>> Index<usize> for Cnf<T, S> {
61 type Output = Clause<T, S>;
62
63 fn index(&self, index: usize) -> &Self::Output {
73 unsafe { self.clauses.get_unchecked(index) }
76 }
77}
78
79impl<T: Literal, S: LiteralStorage<T>> IndexMut<usize> for Cnf<T, S> {
80 fn index_mut(&mut self, index: usize) -> &mut Self::Output {
81 unsafe { self.clauses.get_unchecked_mut(index) }
84 }
85}
86
87impl<T: Literal, S: LiteralStorage<T>> Cnf<T, S> {
88 pub fn new<J: IntoIterator<Item = i32>, I: IntoIterator<Item = J>>(clauses_iter: I) -> Self {
103 let (clauses_vec, max_var_id, vars_vec, lits_vec, num_initial_clauses) = clauses_iter
104 .into_iter()
105 .map(|clause_dimacs| clause_dimacs.into_iter().collect::<Clause<_, _>>())
106 .fold(
107 (Vec::new(), u32::default(), Vec::new(), Vec::new(), 0),
108 |(
109 mut acc_clauses,
110 mut current_max_var,
111 mut acc_vars,
112 mut acc_lits,
113 clause_count,
114 ),
115 clause| {
116 if clause.is_empty() || clause.is_tautology() {
117 return (
118 acc_clauses,
119 current_max_var,
120 acc_vars,
121 acc_lits,
122 clause_count,
123 );
124 }
125
126 let clause_max_var = clause
127 .iter()
128 .map(|l: &T| l.variable())
129 .max()
130 .unwrap_or_default();
131
132 current_max_var = current_max_var.max(clause_max_var);
133
134 acc_lits.extend(clause.iter().copied());
135 acc_vars.extend(clause.iter().map(|l| l.variable()));
136
137 acc_clauses.push(clause);
138
139 (
140 acc_clauses,
141 current_max_var,
142 acc_vars,
143 acc_lits,
144 clause_count + 1,
145 )
146 },
147 );
148
149 Self {
150 clauses: clauses_vec,
151 num_vars: (max_var_id as usize).wrapping_add(1),
152 vars: vars_vec,
153 lits: lits_vec,
154 non_learnt_idx: num_initial_clauses,
155 }
156 }
157
158 pub fn remove(&mut self, idx: usize) {
168 self.clauses.remove(idx);
169 if idx < self.non_learnt_idx {
170 self.non_learnt_idx = self.non_learnt_idx.saturating_sub(1);
171 }
172 }
173
174 pub fn iter(&self) -> impl Iterator<Item = &Clause<T, S>> {
176 self.clauses.iter()
177 }
178
179 pub fn iter_mut(&mut self) -> impl Iterator<Item = &mut Clause<T, S>> {
181 self.clauses.iter_mut()
182 }
183
184 pub fn add_clause(&mut self, clause: Clause<T, S>) {
197 let clause_max_var_id = clause
198 .iter()
199 .map(|l| l.variable())
200 .max()
201 .unwrap_or_default();
202 let clause_max_var_usize = clause_max_var_id as usize;
203
204 let clause_vars = clause.iter().map(|l| l.variable()).collect_vec();
205
206 self.vars.extend(clause_vars);
207 self.lits.extend(clause.iter());
208 self.clauses.push(clause);
209
210 let required_num_vars = clause_max_var_usize.wrapping_add(1);
211 self.num_vars = self.num_vars.max(required_num_vars);
212 }
213
214 pub fn add_clause_vec(&mut self, clause_dimacs: Vec<i32>) {
222 self.add_clause(Clause::from(clause_dimacs));
223 }
224
225 #[must_use]
227 pub const fn len(&self) -> usize {
228 self.clauses.len()
229 }
230
231 #[must_use]
233 pub const fn is_empty(&self) -> bool {
234 self.clauses.is_empty()
235 }
236
237 #[must_use]
251 pub fn verify(&self, solutions: &Solutions) -> bool {
252 self.iter().all(|clause| {
253 clause.iter().any(|&lit| {
254 let lit_i32 = lit.to_i32();
255 NonZeroI32::new(lit_i32).is_some_and(|nonzero_var| solutions.check(nonzero_var))
256 })
257 })
258 }
259
260 pub fn convert<TargetL: Literal, TargetS: LiteralStorage<TargetL>>(
274 &self,
275 ) -> Cnf<TargetL, TargetS> {
276 let clauses_converted = self.clauses.iter().map(Clause::convert).collect_vec();
277
278 let vars_converted = self.vars.clone();
279
280 let lits_converted = self.lits.iter().map(|l| literal::convert(l)).collect_vec();
281
282 Cnf {
283 clauses: clauses_converted,
284 num_vars: self.num_vars,
285 vars: vars_converted,
286 lits: lits_converted,
287 non_learnt_idx: self.non_learnt_idx,
288 }
289 }
290}
291
292impl<L: Literal, S: LiteralStorage<L>> Display for Cnf<L, S> {
293 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
303 let dimacs_num_vars = if self.num_vars > 0 {
304 self.num_vars - 1
305 } else {
306 0
307 };
308 let dimacs_num_clauses = self.non_learnt_idx;
309
310 writeln!(f, "c Generated by CNF module")?;
311 writeln!(f, "p cnf {dimacs_num_vars} {dimacs_num_clauses}")?;
312
313 for clause_idx in 0..self.non_learnt_idx {
314 let clause = &self.clauses[clause_idx];
315 for &lit in clause.iter() {
316 write!(f, "{} ", lit.to_i32())?;
317 }
318 writeln!(f, "0")?;
319 }
320 Ok(())
321 }
322}
323
324impl<L: Literal, S: LiteralStorage<L>> FromIterator<Clause<L, S>> for Cnf<L, S> {
325 fn from_iter<IterClauses: IntoIterator<Item = Clause<L, S>>>(iter: IterClauses) -> Self {
333 let mut cnf = Self::default();
334 let mut max_var_id = u32::default();
335 let mut clause_count = 0;
336
337 for clause in iter {
338 if let Some(clause_max_v) = clause.iter().map(|l| l.variable()).max() {
339 max_var_id = max_var_id.max(clause_max_v);
340 }
341 cnf.vars.extend(clause.iter().map(|l| l.variable()));
342 cnf.lits.extend(clause.iter().copied());
343 cnf.clauses.push(clause);
344 clause_count += 1;
345 }
346 cnf.num_vars = (max_var_id as usize).wrapping_add(1);
347 cnf.non_learnt_idx = clause_count;
348 cnf
349 }
350}
351
352#[must_use]
363pub fn to_cnf<T: Literal, S: LiteralStorage<T>>(expr: &Expr) -> Cnf<T, S> {
364 let cnf_expr = apply_laws(expr);
365 let clauses_vec = to_clauses_recursive(&cnf_expr);
366 Cnf::from_iter(clauses_vec)
367}
368
369fn to_clauses_recursive<T: Literal, S: LiteralStorage<T>>(expr: &Expr) -> Vec<Clause<T, S>> {
372 match expr {
373 Expr::And(e1, e2) => {
374 let mut c1_clauses = to_clauses_recursive(e1);
375 let c2_clauses = to_clauses_recursive(e2);
376 c1_clauses.extend(c2_clauses);
377 c1_clauses
378 }
379 _ => vec![to_clause_recursive(expr)],
380 }
381}
382
383fn to_clause_recursive<T: Literal, S: LiteralStorage<T>>(expr: &Expr) -> Clause<T, S> {
386 match expr {
387 Expr::Or(e1, e2) => {
388 let clause1: Clause<T, S> = to_clause_recursive(e1);
389 let clause2: Clause<T, S> = to_clause_recursive(e2);
390 let mut combined_lits: Vec<T> = Vec::from(&clause1);
391 combined_lits.extend(Vec::from(&clause2));
392 Clause::<T, S>::new(&combined_lits)
393 }
394 _ => Clause::<T, S>::new(&[expr_to_literal(expr)]),
395 }
396}
397
398fn expr_to_literal<T: Literal>(expr: &Expr) -> T {
401 match expr {
402 Expr::Var(i) => T::new(*i, true),
403 Expr::Not(e) => {
404 if let Expr::Var(i) = **e {
405 T::new(i, false)
406 } else {
407 panic!("Expression Not(Non-Variable) encountered where literal expected.");
408 }
409 }
410 _ => panic!("Expression is not a literal (Var or Not(Var))."),
411 }
412}
413
414fn clause_to_expr<T: Literal, S: LiteralStorage<T>>(clause: &Clause<T, S>) -> Expr {
416 let mut iter = clause.iter();
417 let first_lit_expr =
418 literal_to_expr_node(*iter.next().expect("Cannot convert empty clause to Expr"));
419 iter.fold(first_lit_expr, |acc_expr, &literal| {
420 Expr::Or(Box::new(acc_expr), Box::new(literal_to_expr_node(literal)))
421 })
422}
423
424fn literal_to_expr_node<T: Literal>(literal: T) -> Expr {
426 if literal.polarity() {
427 Expr::Var(literal.variable())
428 } else {
429 Expr::Not(Box::new(Expr::Var(literal.variable())))
430 }
431}
432
433impl<T: Literal, S: LiteralStorage<T>> From<Expr> for Cnf<T, S> {
434 fn from(expr: Expr) -> Self {
437 to_cnf(&expr)
438 }
439}
440
441impl<L: Literal, S: LiteralStorage<L>> From<Vec<Clause<L, S>>> for Cnf<L, S> {
442 fn from(clauses: Vec<Clause<L, S>>) -> Self {
445 Self::from_iter(clauses)
446 }
447}
448
449impl<L: Literal, S: LiteralStorage<L>> From<Vec<Vec<i32>>> for Cnf<L, S> {
450 fn from(value: Vec<Vec<i32>>) -> Self {
453 Self::new(value)
454 }
455}
456
457impl<T: Literal, S: LiteralStorage<T>> TryFrom<Cnf<T, S>> for Expr {
458 type Error = &'static str;
459
460 fn try_from(cnf: Cnf<T, S>) -> Result<Self, Self::Error> {
464 let mut iter = cnf.iter();
465 let first_clause_expr =
466 clause_to_expr(iter.next().ok_or("Cannot convert empty CNF to Expr")?);
467
468 iter.try_fold(first_clause_expr, |acc_expr, clause| {
469 Ok(Self::And(
470 Box::new(acc_expr),
471 Box::new(clause_to_expr(clause)),
472 ))
473 })
474 }
475}
476
477#[cfg(test)]
478mod tests {
479 use super::*;
480 use crate::sat::literal::PackedLiteral;
481
482 #[test]
483 fn test_cnf_new_from_dimacs() {
484 let dimacs_clauses = vec![vec![1, -2], vec![-1, 2, 3]];
485 let cnf: Cnf<PackedLiteral> = Cnf::new(dimacs_clauses);
486
487 assert_eq!(cnf.clauses.len(), 2);
488 assert_eq!(cnf.num_vars, 3 + 1);
489 assert_eq!(cnf.non_learnt_idx, 2);
490
491 let first_clause = &cnf.clauses[0];
492 assert_eq!(first_clause.len(), 2);
493 assert!(
494 first_clause
495 .iter()
496 .any(|l| l.variable() == 1_u32 && l.polarity())
497 );
498 assert!(
499 first_clause
500 .iter()
501 .any(|l| l.variable() == 2_u32 && !l.polarity())
502 );
503 }
504
505 #[test]
506 fn test_cnf_add_clause() {
507 let mut cnf: Cnf<PackedLiteral> = Cnf::new(Vec::<Vec<i32>>::new());
508 assert_eq!(cnf.num_vars, 1);
509
510 let clause1_dimacs = vec![1, -2];
511 cnf.add_clause_vec(clause1_dimacs);
512 assert_eq!(cnf.clauses.len(), 1);
513 assert_eq!(cnf.num_vars, 2 + 1);
514
515 let clause2 = Clause::from(vec![-2, 3, 4]);
516 cnf.add_clause(clause2);
517 assert_eq!(cnf.clauses.len(), 2);
518 assert_eq!(cnf.num_vars, 4 + 1);
519 }
520
521 #[test]
522 fn test_cnf_display_dimacs() {
523 let cnf: Cnf<PackedLiteral> = Cnf::new(vec![vec![1, -2], vec![2, 3]]);
524 let dimacs_str = format!("{cnf}");
525 let expected_header = "p cnf 3 2";
526 assert!(
527 dimacs_str.contains(expected_header),
528 "DIMACS header mismatch"
529 );
530 assert!(dimacs_str.contains("1 -2 0"), "Clause 1 mismatch");
531 assert!(dimacs_str.contains("2 3 0"), "Clause 2 mismatch");
532 }
533
534 #[test]
535 fn test_cnf_from_expr() {
536 let expr = Expr::And(
537 Box::new(Expr::Or(
538 Box::new(Expr::Var(1_u32)),
539 Box::new(Expr::Not(Box::new(Expr::Var(2_u32)))),
540 )),
541 Box::new(Expr::Or(
542 Box::new(Expr::Var(2_u32)),
543 Box::new(Expr::Var(3_u32)),
544 )),
545 );
546
547 let cnf: Cnf<PackedLiteral> = Cnf::from(expr);
548 assert_eq!(cnf.clauses.len(), 2);
549 assert_eq!(cnf.num_vars, 3 + 1);
550
551 assert!(cnf.clauses.iter().any(|c| {
552 c.len() == 2
553 && c.iter().any(|l| l.variable() == 1_u32 && l.polarity())
554 && c.iter().any(|l| l.variable() == 2_u32 && !l.polarity())
555 }));
556
557 assert!(cnf.clauses.iter().any(|c| {
558 c.len() == 2
559 && c.iter().any(|l| l.variable() == 2_u32 && l.polarity())
560 && c.iter().any(|l| l.variable() == 3_u32 && l.polarity())
561 }));
562 }
563
564 #[test]
565 fn test_cnf_verify_solution() {
566 let cnf: Cnf<PackedLiteral> = Cnf::new(vec![vec![1, -2], vec![-1, 2, 3]]);
567 let mut solutions = Solutions::default();
568 solutions.add(1.try_into().unwrap());
569 solutions.add((-2).try_into().unwrap());
570 solutions.add(3.try_into().unwrap());
571 assert!(cnf.verify(&solutions));
572
573 let mut solutions_fail = Solutions::default();
574 solutions_fail.add((-1).try_into().unwrap());
575 solutions_fail.add(2.try_into().unwrap());
576 solutions_fail.add((-3).try_into().unwrap());
577 assert!(!cnf.verify(&solutions_fail));
578 }
579
580 #[test]
581 fn test_cnf_new_empty_input() {
582 let cnf_empty: Cnf<PackedLiteral> = Cnf::new(Vec::<Vec<i32>>::new());
583 assert!(cnf_empty.is_empty());
584 assert_eq!(cnf_empty.num_vars, 1);
585 assert_eq!(cnf_empty.non_learnt_idx, 0);
586 }
587
588 #[test]
589 fn test_cnf_new_with_empty_clause() {
590 let cnf_with_empty_clause: Cnf<PackedLiteral> = Cnf::new(vec![Vec::<i32>::new()]);
591 assert_eq!(cnf_with_empty_clause.clauses.len(), 0);
592 }
593}