1use std::{collections::HashMap, iter, rc::Rc};
2
3use crate::{Gate, Literal, Operation};
4
5pub fn generate_cnf<'a>(
17 gate: &'a Gate,
18 new_var: &mut impl FnMut() -> String,
19) -> impl Iterator<Item = Vec<Literal>> + 'a {
20 let lit_for_gate_id: HashMap<_, _> = gate
22 .iter()
23 .map(|n| {
24 let var = match n.operation() {
25 Operation::Variable(name) => Literal::Pos(name.clone()),
26 _ => Literal::Pos(Rc::new(new_var())),
27 };
28 (n.id(), var)
29 })
30 .collect();
31 let lit_for_gate = move |gate: &Gate| lit_for_gate_id[&gate.id()].clone();
32 let output_var = lit_for_gate(gate);
33 gate.into_iter()
35 .flat_map(move |n| {
36 let var = lit_for_gate(n);
37 match n.operation() {
38 Operation::Variable(_) => vec![],
39 Operation::Constant(true) => vec![vec![var]],
40 Operation::Constant(false) => vec![vec![!&var]],
41 Operation::Conjunction(left, right) => {
42 let left_var = lit_for_gate(left);
43 let right_var = lit_for_gate(right);
44 vec![
45 vec![!&left_var, !&right_var, var.clone()],
46 vec![left_var.clone(), !&var],
47 vec![right_var.clone(), !&var],
48 ]
49 }
50 Operation::Disjunction(left, right) => {
51 let left_var = lit_for_gate(left);
52 let right_var = lit_for_gate(right);
53 vec![
54 vec![left_var.clone(), right_var.clone(), !&var],
55 vec![!&left_var, var.clone()],
56 vec![!&right_var, var.clone()],
57 ]
58 }
59 Operation::Xor(left, right) => {
60 let left_var = lit_for_gate(left);
61 let right_var = lit_for_gate(right);
62 vec![
63 vec![left_var.clone(), right_var.clone(), !&var],
64 vec![left_var.clone(), !&right_var, var.clone()],
65 vec![!&left_var, right_var.clone(), var.clone()],
66 vec![!&left_var, !&right_var, !&var],
67 ]
68 }
69 Operation::Negation(inner) => {
70 let inner_var = lit_for_gate(inner);
71 vec![
72 vec![inner_var.clone(), var.clone()],
73 vec![!&inner_var, !&var],
74 ]
75 }
76 }
77 })
78 .chain(iter::once(vec![output_var]))
80}
81
82#[cfg(test)]
83mod test {
84 use itertools::Itertools;
85
86 use super::*;
87
88 #[derive(Default)]
89 struct VarGen {
90 counter: u32,
91 }
92
93 impl VarGen {
94 fn next(&mut self) -> String {
95 let name = format!("x{}", self.counter);
96 self.counter += 1;
97 name
98 }
99 }
100
101 fn to_cnf_string(gate: &Gate, new_var: &mut impl FnMut() -> String) -> String {
102 generate_cnf(gate, new_var)
103 .map(|clause| format!("({})", clause.iter().format(" \\/ ")))
104 .format(" /\\ ")
105 .to_string()
106 }
107
108 #[test]
109 fn test_to_cnf() {
110 let mut var_gen = VarGen::default();
111 let mut new_var = || var_gen.next();
112 let gate = Gate::from("a");
113 assert_eq!(to_cnf_string(&gate, &mut new_var), "(a)".to_string());
114 }
115
116 #[test]
117 fn test_to_cnf_conjunction() {
118 let mut var_gen = VarGen::default();
119 let mut new_var = || var_gen.next();
120 let gate = Gate::from("a") & Gate::from("b");
121 assert_eq!(
122 to_cnf_string(&gate, &mut new_var),
123 "(-a \\/ -b \\/ x0) /\\ (a \\/ -x0) /\\ (b \\/ -x0) /\\ (x0)".to_string()
124 );
125 }
126
127 #[test]
128 fn test_to_cnf_disjunction() {
129 let mut var_gen = VarGen::default();
130 let mut new_var = || var_gen.next();
131 let gate = Gate::from("a") | Gate::from("b");
132 assert_eq!(
133 to_cnf_string(&gate, &mut new_var),
134 "(a \\/ b \\/ -x0) /\\ (-a \\/ x0) /\\ (-b \\/ x0) /\\ (x0)".to_string()
135 );
136 }
137
138 #[test]
139 fn test_clause_reuse() {
140 let mut var_gen = VarGen::default();
141 let mut new_var = || var_gen.next();
142 let v = Gate::from("a");
143 let x = v.clone() | v;
144 let y = x.clone() & (!x);
145 assert_eq!(
146 to_cnf_string(&y, &mut new_var),
147 "(-x1 \\/ -x2 \\/ x0) /\\ (x1 \\/ -x0) /\\ (x2 \\/ -x0) /\\ (a \\/ a \\/ -x1) /\\ (-a \\/ x1) /\\ (-a \\/ x1) /\\ (x1 \\/ x2) /\\ (-x1 \\/ -x2) /\\ (x0)".to_string()
148 );
149 }
150}