1use crate::models::formula::Satisfiability;
12use crate::models::graph::KColoring;
13use crate::reduction;
14use crate::rules::sat_maximumindependentset::BoolVar;
15use crate::rules::traits::{ReduceTo, ReductionResult};
16use crate::topology::SimpleGraph;
17use crate::variant::K3;
18use std::collections::HashMap;
19
20struct SATColoringConstructor {
22 edges: Vec<(usize, usize)>,
24 num_vertices: usize,
26 pos_vertices: Vec<usize>,
28 neg_vertices: Vec<usize>,
30 vmap: HashMap<(usize, bool), usize>,
32}
33
34impl SATColoringConstructor {
35 fn new(num_vars: usize) -> Self {
43 let num_vertices = 2 * num_vars + 3;
44 let mut edges = Vec::new();
45
46 edges.push((0, 1));
48 edges.push((0, 2));
49 edges.push((1, 2));
50
51 let mut pos_vertices = Vec::with_capacity(num_vars);
53 let mut neg_vertices = Vec::with_capacity(num_vars);
54 let mut vmap = HashMap::new();
55
56 for i in 0..num_vars {
57 let pos_v = 3 + i;
58 let neg_v = 3 + num_vars + i;
59 pos_vertices.push(pos_v);
60 neg_vertices.push(neg_v);
61
62 edges.push((pos_v, 2));
64 edges.push((neg_v, 2));
65
66 edges.push((pos_v, neg_v));
68
69 vmap.insert((i, false), pos_v); vmap.insert((i, true), neg_v); }
73
74 Self {
75 edges,
76 num_vertices,
77 pos_vertices,
78 neg_vertices,
79 vmap,
80 }
81 }
82
83 fn true_vertex(&self) -> usize {
85 0
86 }
87
88 fn false_vertex(&self) -> usize {
90 1
91 }
92
93 fn aux_vertex(&self) -> usize {
95 2
96 }
97
98 fn attach_to_aux(&mut self, idx: usize) {
100 self.add_edge(idx, self.aux_vertex());
101 }
102
103 fn attach_to_false(&mut self, idx: usize) {
105 self.add_edge(idx, self.false_vertex());
106 }
107
108 fn attach_to_true(&mut self, idx: usize) {
110 self.add_edge(idx, self.true_vertex());
111 }
112
113 fn add_edge(&mut self, u: usize, v: usize) {
115 self.edges.push((u, v));
116 }
117
118 fn add_vertices(&mut self, n: usize) -> Vec<usize> {
120 let start = self.num_vertices;
121 self.num_vertices += n;
122 (start..self.num_vertices).collect()
123 }
124
125 fn set_true(&mut self, idx: usize) {
128 self.attach_to_aux(idx);
129 self.attach_to_false(idx);
130 }
131
132 fn get_vertex(&self, var: &BoolVar) -> usize {
134 self.vmap[&(var.name, var.neg)]
135 }
136
137 fn add_clause(&mut self, literals: &[i64]) {
141 assert!(
142 !literals.is_empty(),
143 "Clause must have at least one literal"
144 );
145
146 let first_var = BoolVar::from_literal(literals[0]);
147 let mut output_node = self.get_vertex(&first_var);
148
149 for &lit in &literals[1..] {
151 let var = BoolVar::from_literal(lit);
152 let input2 = self.get_vertex(&var);
153 output_node = self.add_or_gadget(output_node, input2);
154 }
155
156 self.set_true(output_node);
158 }
159
160 fn add_or_gadget(&mut self, input1: usize, input2: usize) -> usize {
169 let new_vertices = self.add_vertices(5);
171 let ancilla1 = new_vertices[0];
172 let ancilla2 = new_vertices[1];
173 let entrance1 = new_vertices[2];
174 let entrance2 = new_vertices[3];
175 let output = new_vertices[4];
176
177 self.attach_to_aux(output);
179
180 self.attach_to_true(ancilla1);
182
183 self.add_edge(ancilla1, ancilla2);
188 self.add_edge(ancilla2, input1);
189 self.add_edge(ancilla2, input2);
190 self.add_edge(entrance1, entrance2);
191 self.add_edge(output, ancilla1);
192 self.add_edge(input1, entrance2);
193 self.add_edge(input2, entrance1);
194 self.add_edge(entrance1, output);
195 self.add_edge(entrance2, output);
196
197 output
198 }
199
200 fn build_coloring(&self) -> KColoring<K3, SimpleGraph> {
202 KColoring::<K3, _>::new(SimpleGraph::new(self.num_vertices, self.edges.clone()))
203 }
204}
205
206#[derive(Debug, Clone)]
213pub struct ReductionSATToColoring {
214 target: KColoring<K3, SimpleGraph>,
216 pos_vertices: Vec<usize>,
218 neg_vertices: Vec<usize>,
220 num_source_variables: usize,
222 num_clauses: usize,
224}
225
226impl ReductionResult for ReductionSATToColoring {
227 type Source = Satisfiability;
228 type Target = KColoring<K3, SimpleGraph>;
229
230 fn target_problem(&self) -> &Self::Target {
231 &self.target
232 }
233
234 fn extract_solution(
244 &self,
245 target_solution: &<Self::Target as crate::traits::Problem>::Solution,
246 ) -> crate::rules::ExtractionResult<<Self::Source as crate::traits::Problem>::Solution> {
247 crate::rules::traits::validate_target_solution(self.target_problem(), target_solution)?;
248
249 Ok({
250 let true_color = target_solution[0];
253 let false_color = target_solution[1];
254 let aux_color = target_solution[2];
255
256 if true_color == false_color || true_color == aux_color || false_color == aux_color {
257 return Err(crate::rules::ExtractionError::invalid(
258 "target coloring does not distinguish true, false, and auxiliary colors",
259 ));
260 }
261
262 let mut assignment = vec![false; self.num_source_variables];
263
264 for (i, &pos_vertex) in self.pos_vertices.iter().enumerate() {
265 let vertex_color = target_solution[pos_vertex];
266
267 if vertex_color == aux_color {
269 return Err(crate::rules::ExtractionError::invalid(format!(
270 "variable {i} has the auxiliary color"
271 )));
272 }
273
274 assignment[i] = vertex_color == true_color;
277 }
278
279 assignment
280 })
281 }
282}
283
284impl ReductionSATToColoring {
285 pub fn num_clauses(&self) -> usize {
287 self.num_clauses
288 }
289
290 pub fn pos_vertices(&self) -> &[usize] {
292 &self.pos_vertices
293 }
294
295 pub fn neg_vertices(&self) -> &[usize] {
297 &self.neg_vertices
298 }
299}
300
301#[reduction(
302 transform = exact {
303 num_vertices = "2 * num_vars + 3 + 5 * (num_literals - num_clauses)",
304 num_edges = "3 + 3 * num_vars + 11 * num_literals - 9 * num_clauses",
305 num_colors = "3",
306 }
307)]
308impl ReduceTo<KColoring<K3, SimpleGraph>> for Satisfiability {
309 type Result = ReductionSATToColoring;
310
311 fn reduce_to(&self) -> Result<Self::Result, crate::rules::ReductionError> {
312 let mut constructor = SATColoringConstructor::new(self.num_vars());
313
314 for clause in self.clauses() {
316 constructor.add_clause(&clause.literals);
317 }
318
319 let target = constructor.build_coloring();
320
321 Ok(ReductionSATToColoring {
322 target,
323 pos_vertices: constructor.pos_vertices,
324 neg_vertices: constructor.neg_vertices,
325 num_source_variables: self.num_vars(),
326 num_clauses: self.num_clauses(),
327 })
328 }
329}
330
331#[cfg(feature = "example-db")]
332pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
333 use crate::export::SolutionPair;
334 use crate::models::formula::{CNFClause, Satisfiability};
335
336 vec![crate::example_db::specs::RuleExampleSpec {
337 id: "satisfiability_to_kcoloring",
338 build: || {
339 let source = Satisfiability::new(
340 5,
341 vec![
342 CNFClause::new(vec![1]),
343 CNFClause::new(vec![-3]),
344 CNFClause::new(vec![5]),
345 ],
346 );
347 crate::example_db::specs::rule_example_with_witness::<_, KColoring<K3, SimpleGraph>>(
348 source,
349 SolutionPair {
350 source_config: serde_json::json!(vec![true, true, false, true, true]),
351 target_config: serde_json::json!(vec![2, 1, 0, 2, 2, 1, 2, 2, 1, 1, 2, 1, 1]),
352 },
353 )
354 },
355 }]
356}
357
358#[cfg(test)]
359#[path = "../unit_tests/rules/sat_coloring.rs"]
360mod tests;