problemreductions/rules/
sat_coloring.rs1use 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: &[i32]) {
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(&self, target_solution: &[usize]) -> Vec<usize> {
244 assert!(
247 target_solution.len() >= 3,
248 "Invalid solution: coloring must have at least 3 vertices"
249 );
250 let true_color = target_solution[0];
251 let false_color = target_solution[1];
252 let aux_color = target_solution[2];
253
254 assert!(
256 true_color != false_color && true_color != aux_color,
257 "Invalid coloring solution: special vertices must have distinct colors"
258 );
259
260 let mut assignment = vec![0usize; self.num_source_variables];
261
262 for (i, &pos_vertex) in self.pos_vertices.iter().enumerate() {
263 let vertex_color = target_solution[pos_vertex];
264
265 assert!(
267 vertex_color != aux_color,
268 "Invalid coloring solution: variable vertex has auxiliary color"
269 );
270
271 assignment[i] = if vertex_color == true_color { 1 } else { 0 };
274 }
275
276 assignment
277 }
278}
279
280impl ReductionSATToColoring {
281 pub fn num_clauses(&self) -> usize {
283 self.num_clauses
284 }
285
286 pub fn pos_vertices(&self) -> &[usize] {
288 &self.pos_vertices
289 }
290
291 pub fn neg_vertices(&self) -> &[usize] {
293 &self.neg_vertices
294 }
295}
296
297#[reduction(
298 overhead = {
299 num_vertices = "num_vars + num_literals",
300 num_edges = "num_vars + num_literals",
301 }
302)]
303impl ReduceTo<KColoring<K3, SimpleGraph>> for Satisfiability {
304 type Result = ReductionSATToColoring;
305
306 fn reduce_to(&self) -> Self::Result {
307 let mut constructor = SATColoringConstructor::new(self.num_vars());
308
309 for clause in self.clauses() {
311 constructor.add_clause(&clause.literals);
312 }
313
314 let target = constructor.build_coloring();
315
316 ReductionSATToColoring {
317 target,
318 pos_vertices: constructor.pos_vertices,
319 neg_vertices: constructor.neg_vertices,
320 num_source_variables: self.num_vars(),
321 num_clauses: self.num_clauses(),
322 }
323 }
324}
325
326#[cfg(test)]
327#[path = "../unit_tests/rules/sat_coloring.rs"]
328mod tests;