problemreductions/rules/
sat_ksat.rs1use crate::models::formula::{CNFClause, KSatisfiability, Satisfiability};
10use crate::reduction;
11use crate::rules::traits::{ReduceTo, ReductionResult};
12use crate::variant::{KValue, K2, K3, KN};
13
14#[derive(Debug, Clone)]
19pub struct ReductionSATToKSAT<K: KValue> {
20 source_num_vars: usize,
22 target: KSatisfiability<K>,
24}
25
26impl<K: KValue> ReductionResult for ReductionSATToKSAT<K> {
27 type Source = Satisfiability;
28 type Target = KSatisfiability<K>;
29
30 fn target_problem(&self) -> &Self::Target {
31 &self.target
32 }
33
34 fn extract_solution(&self, target_solution: &[usize]) -> Vec<usize> {
35 target_solution[..self.source_num_vars].to_vec()
37 }
38}
39
40fn add_clause_to_ksat(
56 k: usize,
57 clause: &CNFClause,
58 result_clauses: &mut Vec<CNFClause>,
59 mut next_var: i32,
60) -> i32 {
61 let len = clause.len();
62
63 if len == k {
64 result_clauses.push(clause.clone());
66 } else if len < k {
67 let ancilla = next_var;
71 next_var += 1;
72
73 let mut lits_pos = clause.literals.clone();
75 lits_pos.push(ancilla);
76 next_var = add_clause_to_ksat(k, &CNFClause::new(lits_pos), result_clauses, next_var);
77
78 let mut lits_neg = clause.literals.clone();
80 lits_neg.push(-ancilla);
81 next_var = add_clause_to_ksat(k, &CNFClause::new(lits_neg), result_clauses, next_var);
82 } else {
83 assert!(k >= 3, "K must be at least 3 for splitting");
86
87 let ancilla = next_var;
88 next_var += 1;
89
90 let mut first_lits: Vec<i32> = clause.literals[..k - 1].to_vec();
92 first_lits.push(ancilla);
93 result_clauses.push(CNFClause::new(first_lits));
94
95 let mut remaining_lits = vec![-ancilla];
97 remaining_lits.extend_from_slice(&clause.literals[k - 1..]);
98 let remaining_clause = CNFClause::new(remaining_lits);
99
100 next_var = add_clause_to_ksat(k, &remaining_clause, result_clauses, next_var);
102 }
103
104 next_var
105}
106
107macro_rules! impl_sat_to_ksat {
112 ($ktype:ty, $k:expr) => {
113 #[rustfmt::skip]
114 #[reduction(overhead = {
115 num_clauses = "4 * num_clauses + num_literals",
116 num_vars = "num_vars + 3 * num_clauses + num_literals",
117 })]
118 impl ReduceTo<KSatisfiability<$ktype>> for Satisfiability {
119 type Result = ReductionSATToKSAT<$ktype>;
120
121 fn reduce_to(&self) -> Self::Result {
122 let source_num_vars = self.num_vars();
123 let mut result_clauses = Vec::new();
124 let mut next_var = (source_num_vars + 1) as i32; for clause in self.clauses() {
127 next_var = add_clause_to_ksat($k, clause, &mut result_clauses, next_var);
128 }
129
130 let total_vars = (next_var - 1) as usize;
132
133 let target = KSatisfiability::<$ktype>::new(total_vars, result_clauses);
134
135 ReductionSATToKSAT {
136 source_num_vars,
137 target,
138 }
139 }
140 }
141 };
142}
143
144impl_sat_to_ksat!(K3, 3);
146
147#[derive(Debug, Clone)]
151pub struct ReductionKSATToSAT<K: KValue> {
152 target: Satisfiability,
154 _phantom: std::marker::PhantomData<K>,
155}
156
157impl<K: KValue> ReductionResult for ReductionKSATToSAT<K> {
158 type Source = KSatisfiability<K>;
159 type Target = Satisfiability;
160
161 fn target_problem(&self) -> &Self::Target {
162 &self.target
163 }
164
165 fn extract_solution(&self, target_solution: &[usize]) -> Vec<usize> {
166 target_solution.to_vec()
168 }
169}
170
171fn reduce_ksat_to_sat<K: KValue>(ksat: &KSatisfiability<K>) -> ReductionKSATToSAT<K> {
173 let clauses = ksat.clauses().to_vec();
174 let target = Satisfiability::new(ksat.num_vars(), clauses);
175
176 ReductionKSATToSAT {
177 target,
178 _phantom: std::marker::PhantomData,
179 }
180}
181
182macro_rules! impl_ksat_to_sat {
185 ($ktype:ty) => {
186#[rustfmt::skip]
187 #[reduction(overhead = {
188 num_clauses = "num_clauses",
189 num_vars = "num_vars",
190 num_literals = "num_literals",
191 })]
192 impl ReduceTo<Satisfiability> for KSatisfiability<$ktype> {
193 type Result = ReductionKSATToSAT<$ktype>;
194
195 fn reduce_to(&self) -> Self::Result {
196 reduce_ksat_to_sat(self)
197 }
198 }
199 };
200}
201
202impl_ksat_to_sat!(KN);
204
205impl ReduceTo<Satisfiability> for KSatisfiability<K3> {
208 type Result = ReductionKSATToSAT<K3>;
209 fn reduce_to(&self) -> Self::Result {
210 reduce_ksat_to_sat(self)
211 }
212}
213
214impl ReduceTo<Satisfiability> for KSatisfiability<K2> {
215 type Result = ReductionKSATToSAT<K2>;
216 fn reduce_to(&self) -> Self::Result {
217 reduce_ksat_to_sat(self)
218 }
219}
220
221#[cfg(test)]
222#[path = "../unit_tests/rules/sat_ksat.rs"]
223mod tests;