1use crate::models::formula::{KSatisfiability, NAESatisfiability, Satisfiability};
12use crate::models::graph::MonochromaticTriangle;
13use crate::reduction;
14use crate::rules::sat_helpers::SatVariableAllocator;
15use crate::rules::satisfiability_naesatisfiability::ReductionSATToNAESAT;
16use crate::rules::traits::{ReduceTo, ReductionResult};
17use crate::topology::SimpleGraph;
18use crate::variant::K3;
19
20fn add_equality_sender(
27 edges: &mut Vec<(usize, usize)>,
28 first: (usize, usize),
29 second: (usize, usize),
30 private: usize,
31) {
32 let [u, v, w] = [private, private + 1, private + 2];
33 edges.extend([(u, v), (u, w), (v, w)]);
34 for endpoint in [first.0, first.1, second.0, second.1] {
35 edges.extend([(endpoint, u), (endpoint, v), (endpoint, w)]);
36 }
37}
38
39#[derive(Debug, Clone)]
41pub struct Reduction3SATToMonochromaticTriangle {
42 target: MonochromaticTriangle<SimpleGraph>,
43 nae_reduction: ReductionSATToNAESAT,
44}
45
46impl ReductionResult for Reduction3SATToMonochromaticTriangle {
47 type Source = KSatisfiability<K3>;
48 type Target = MonochromaticTriangle<SimpleGraph>;
49
50 fn target_problem(&self) -> &Self::Target {
51 &self.target
52 }
53
54 fn extract_solution(
55 &self,
56 target_solution: &<Self::Target as crate::traits::Problem>::Solution,
57 ) -> crate::rules::ExtractionResult<<Self::Source as crate::traits::Problem>::Solution> {
58 crate::rules::traits::validate_target_solution(self.target_problem(), target_solution)?;
59 let nae_solution = (0..self.nae_reduction.target_problem().num_vars())
60 .map(|index| target_solution[2 * index])
61 .collect();
62 self.nae_reduction.extract_solution(&nae_solution)
65 }
66}
67
68#[reduction(
69 transform = upper_bound {
70 num_vertices = "16 * num_vars + 40 * num_clauses + 16",
71 num_edges = "50 * num_vars + 146 * num_clauses + 50",
72 num_triangles = "58 * num_vars + 174 * num_clauses + 58",
73 }
74)]
75impl ReduceTo<MonochromaticTriangle<SimpleGraph>> for KSatisfiability<K3> {
76 type Result = Reduction3SATToMonochromaticTriangle;
77
78 fn reduce_to(&self) -> Result<Self::Result, crate::rules::ReductionError> {
79 let sat = ReduceTo::<Satisfiability>::reduce_to(self)?;
80 let nae_reduction = ReduceTo::<NAESatisfiability>::reduce_to(sat.target_problem())?;
81 let nae = nae_reduction.target_problem();
82 let auxiliary_count = nae.clauses().iter().filter(|c| c.len() == 4).count();
83 let overflow = || {
84 crate::rules::ReductionError::integer_overflow::<Self, MonochromaticTriangle<SimpleGraph>>(
85 "computing signal-sender graph size",
86 )
87 };
88 let variable_count = nae
89 .num_vars()
90 .checked_add(auxiliary_count)
91 .ok_or_else(overflow)?;
92 let triple_count = variable_count
93 .checked_add(nae.num_clauses())
94 .and_then(|n| n.checked_add(auxiliary_count))
95 .ok_or_else(overflow)?;
96 let num_vertices = variable_count
97 .checked_mul(4)
98 .and_then(|n| triple_count.checked_mul(12).and_then(|t| n.checked_add(t)))
99 .ok_or_else(overflow)?;
100 let num_edges = variable_count
101 .checked_mul(2)
102 .and_then(|n| triple_count.checked_mul(48).and_then(|t| n.checked_add(t)))
103 .ok_or_else(overflow)?;
104
105 let mut variables =
106 SatVariableAllocator::new("KSatisfiability -> MonochromaticTriangle", nae.num_vars())
107 .map_err(
108 crate::rules::ReductionError::construction::<
109 Self,
110 MonochromaticTriangle<SimpleGraph>,
111 >,
112 )?;
113 let mut triples = Vec::with_capacity(triple_count);
114 for index in 0..variable_count {
115 let literal = i64::try_from(index + 1).map_err(|_| overflow())?;
116 triples.push([literal, literal, -literal]);
117 }
118 for clause in nae.clauses() {
119 let literals = &clause.literals;
120 if literals.len() == 4 {
121 let z = variables.allocate().map_err(
122 crate::rules::ReductionError::construction::<
123 Self,
124 MonochromaticTriangle<SimpleGraph>,
125 >,
126 )?;
127 triples.push([literals[0], literals[1], z]);
128 triples.push([-z, literals[2], literals[3]]);
129 } else {
130 triples.push([literals[0], literals[1], literals[literals.len() - 1]]);
133 }
134 }
135
136 let mut edges = Vec::with_capacity(num_edges);
137 for index in 0..variable_count {
138 edges.extend([(4 * index, 4 * index + 1), (4 * index + 2, 4 * index + 3)]);
139 }
140 let mut next_vertex = 4 * variable_count;
142 for triple in triples {
143 let [a, b, c] = [next_vertex, next_vertex + 1, next_vertex + 2];
144 next_vertex += 3;
145 let sides = [(a, b), (a, c), (b, c)];
146 edges.extend(sides);
147 for (literal, side) in triple.into_iter().zip(sides) {
148 let index = usize::try_from(literal.unsigned_abs() - 1)
149 .expect("validated SAT variable index fits usize");
150 let endpoint = 4 * index + if literal < 0 { 2 } else { 0 };
151 add_equality_sender(&mut edges, (endpoint, endpoint + 1), side, next_vertex);
152 next_vertex += 3;
153 }
154 }
155 debug_assert_eq!(next_vertex, num_vertices);
156 debug_assert_eq!(edges.len(), num_edges);
157 let target = MonochromaticTriangle::new(SimpleGraph::new(num_vertices, edges));
158 Ok(Reduction3SATToMonochromaticTriangle {
159 target,
160 nae_reduction,
161 })
162 }
163}
164
165#[cfg(feature = "example-db")]
166pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
167 use crate::export::SolutionPair;
168 use crate::models::formula::CNFClause;
169 use crate::solvers::ILPSolver;
170
171 vec![crate::example_db::specs::RuleExampleSpec {
172 id: "ksatisfiability_to_monochromatictriangle",
173 build: || {
174 let source = KSatisfiability::<K3>::new(3, vec![CNFClause::new(vec![1, 2, 3])]);
175 let reduction = ReduceTo::<MonochromaticTriangle<SimpleGraph>>::reduce_to(&source)
176 .expect("reduction should succeed");
177 let target_config = ILPSolver::new()
178 .solve(reduction.target_problem())
179 .expect("canonical target must be colourable");
180 let source_config = reduction.extract_solution(&target_config).unwrap();
181 crate::example_db::specs::assemble_rule_example(
182 &source,
183 reduction.target_problem(),
184 vec![SolutionPair {
185 source_config: serde_json::to_value(source_config)
186 .expect("solution serialization must succeed"),
187 target_config: serde_json::to_value(target_config)
188 .expect("solution serialization must succeed"),
189 }],
190 )
191 },
192 }]
193}
194
195#[cfg(test)]
196#[path = "../unit_tests/rules/ksatisfiability_monochromatictriangle.rs"]
197mod tests;