problemreductions/rules/
ksatisfiability_monochromatictriangle.rs1use crate::models::formula::KSatisfiability;
10use crate::models::graph::MonochromaticTriangle;
11use crate::reduction;
12use crate::rules::traits::{ReduceTo, ReductionResult};
13use crate::topology::SimpleGraph;
14use crate::traits::Problem;
15use crate::variant::K3;
16use std::collections::HashMap;
17
18fn normalized_edge(u: usize, v: usize) -> (usize, usize) {
19 if u < v {
20 (u, v)
21 } else {
22 (v, u)
23 }
24}
25
26fn literal_vertex(num_vars: usize, literal: i32) -> usize {
27 if literal > 0 {
28 literal as usize - 1
29 } else {
30 num_vars + literal.unsigned_abs() as usize - 1
31 }
32}
33
34#[derive(Debug, Clone)]
36pub struct Reduction3SATToMonochromaticTriangle {
37 target: MonochromaticTriangle<SimpleGraph>,
38 source: KSatisfiability<K3>,
39 negation_edge_indices: Vec<usize>,
40}
41
42impl ReductionResult for Reduction3SATToMonochromaticTriangle {
43 type Source = KSatisfiability<K3>;
44 type Target = MonochromaticTriangle<SimpleGraph>;
45
46 fn target_problem(&self) -> &Self::Target {
47 &self.target
48 }
49
50 fn extract_solution(&self, target_solution: &[usize]) -> Vec<usize> {
51 let direct: Vec<usize> = self
52 .negation_edge_indices
53 .iter()
54 .map(
55 |&edge_idx| match target_solution.get(edge_idx).copied().unwrap_or(1) {
56 0 => 1,
57 _ => 0,
58 },
59 )
60 .collect();
61 if self.source.evaluate(&direct).0 {
62 return direct;
63 }
64
65 let complement: Vec<usize> = direct.iter().map(|&value| 1 - value).collect();
66 if self.source.evaluate(&complement).0 {
67 return complement;
68 }
69
70 direct
71 }
72}
73
74#[reduction(
75 overhead = {
76 num_vertices = "2 * num_vars + 3 * num_clauses",
77 num_edges = "num_vars + 9 * num_clauses",
78 }
79)]
80impl ReduceTo<MonochromaticTriangle<SimpleGraph>> for KSatisfiability<K3> {
81 type Result = Reduction3SATToMonochromaticTriangle;
82
83 fn reduce_to(&self) -> Self::Result {
84 let num_vars = self.num_vars();
85 let num_clauses = self.num_clauses();
86 let mut edges = Vec::with_capacity(num_vars + 9 * num_clauses);
87
88 for var in 0..num_vars {
89 edges.push((var, num_vars + var));
90 }
91
92 for (clause_idx, clause) in self.clauses().iter().enumerate() {
93 let clause_base = 2 * num_vars + 3 * clause_idx;
94 let m12 = clause_base;
95 let m13 = clause_base + 1;
96 let m23 = clause_base + 2;
97 let literal_vertices: Vec<usize> = clause
98 .literals
99 .iter()
100 .map(|&literal| literal_vertex(num_vars, literal))
101 .collect();
102 let v1 = literal_vertices[0];
103 let v2 = literal_vertices[1];
104 let v3 = literal_vertices[2];
105
106 edges.extend_from_slice(&[
107 (v1, m12),
108 (v2, m12),
109 (v1, m13),
110 (v3, m13),
111 (v2, m23),
112 (v3, m23),
113 (m12, m13),
114 (m12, m23),
115 (m13, m23),
116 ]);
117 }
118
119 let target =
120 MonochromaticTriangle::new(SimpleGraph::new(2 * num_vars + 3 * num_clauses, edges));
121 let edge_indices: HashMap<(usize, usize), usize> = target
122 .edge_list()
123 .iter()
124 .copied()
125 .enumerate()
126 .map(|(idx, (u, v))| (normalized_edge(u, v), idx))
127 .collect();
128 let negation_edge_indices = (0..num_vars)
129 .map(|var| edge_indices[&normalized_edge(var, num_vars + var)])
130 .collect();
131
132 Reduction3SATToMonochromaticTriangle {
133 target,
134 source: self.clone(),
135 negation_edge_indices,
136 }
137 }
138}
139
140#[cfg(feature = "example-db")]
141pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
142 use crate::export::SolutionPair;
143 use crate::models::formula::CNFClause;
144 use crate::solvers::BruteForce;
145
146 vec![crate::example_db::specs::RuleExampleSpec {
147 id: "ksatisfiability_to_monochromatictriangle",
148 build: || {
149 let source = KSatisfiability::<K3>::new(3, vec![CNFClause::new(vec![1, 2, 3])]);
150 let reduction =
151 <KSatisfiability<K3> as ReduceTo<MonochromaticTriangle<SimpleGraph>>>::reduce_to(
152 &source,
153 );
154 let target_config = BruteForce::new()
155 .find_witness(reduction.target_problem())
156 .expect("canonical MonochromaticTriangle example must be feasible");
157 let source_config = reduction.extract_solution(&target_config);
158 crate::example_db::specs::assemble_rule_example(
159 &source,
160 reduction.target_problem(),
161 vec![SolutionPair {
162 source_config,
163 target_config,
164 }],
165 )
166 },
167 }]
168}
169
170#[cfg(test)]
171#[path = "../unit_tests/rules/ksatisfiability_monochromatictriangle.rs"]
172mod tests;