1use crate::models::graph::{BicliqueCover, KColoring};
33use crate::reduction;
34use crate::rules::traits::{ReduceTo, ReductionResult};
35use crate::topology::{BipartiteGraph, Graph, SimpleGraph};
36use crate::variant::KN;
37use std::collections::BTreeSet;
38
39#[derive(Debug, Clone)]
41pub struct ReductionKColoringToBicliqueCover {
42 target: BicliqueCover,
43 num_vertices: usize,
47 num_colors: usize,
50}
51
52impl ReductionResult for ReductionKColoringToBicliqueCover {
53 type Source = KColoring<KN, SimpleGraph>;
54 type Target = BicliqueCover;
55
56 fn target_problem(&self) -> &BicliqueCover {
57 &self.target
58 }
59
60 fn extract_solution(
72 &self,
73 target_solution: &<Self::Target as crate::traits::Problem>::Solution,
74 ) -> crate::rules::ExtractionResult<<Self::Source as crate::traits::Problem>::Solution> {
75 crate::rules::traits::validate_target_witness(
76 self.target_problem(),
77 target_solution,
78 |value| value.0.is_some(),
79 "target configuration is not a biclique cover",
80 )?;
81
82 Ok({
83 let n = self.num_vertices;
84 let k = self.target.k();
85 let left_size = 2 * n;
86
87 let mut diagonal_biclique = Vec::with_capacity(n);
90 for v in 0..n {
91 let a_v = v;
92 let b_v = left_size + v;
93 let biclique = (0..k)
94 .find(|&r| target_solution[r][a_v] && target_solution[r][b_v])
95 .ok_or_else(|| {
96 crate::rules::ExtractionError::invalid(format!(
97 "target cover leaves diagonal gadget edge {v} uncovered"
98 ))
99 })?;
100 diagonal_biclique.push(biclique);
101 }
102
103 let mut color_of_biclique: std::collections::HashMap<usize, usize> =
105 std::collections::HashMap::new();
106 let mut coloring = Vec::with_capacity(n);
107 for biclique in diagonal_biclique {
108 let next_color = color_of_biclique.len();
109 let color = *color_of_biclique.entry(biclique).or_insert(next_color);
110 if color >= self.num_colors {
111 return Err(crate::rules::ExtractionError::invalid(format!(
112 "target cover uses more than {} diagonal bicliques",
113 self.num_colors
114 )));
115 }
116 coloring.push(color);
117 }
118 coloring
119 })
120 }
121}
122
123#[crate::aggregate_reduction]
124impl crate::rules::AggregateReductionResult for ReductionKColoringToBicliqueCover {
125 type Source = KColoring<KN, SimpleGraph>;
126 type Target = BicliqueCover;
127
128 fn target_problem(&self) -> &Self::Target {
129 &self.target
130 }
131
132 fn extract_value(&self, value: crate::types::Min<i64>) -> crate::types::Or {
133 crate::types::Or(value.0.is_some())
134 }
135}
136
137#[reduction(
138 transform = upper_bound {
139 left_size = "2 * num_vertices + 1",
140 num_vertices = "4 * num_vertices + 2",
141 num_edges = "2 * num_vertices^2 + num_vertices + 1",
142 rank = "2 * num_vertices",
143 right_size = "2 * num_vertices + 1",
144 }
145)]
146impl ReduceTo<BicliqueCover> for KColoring<KN, SimpleGraph> {
147 type Result = ReductionKColoringToBicliqueCover;
148
149 fn reduce_to(&self) -> Result<Self::Result, crate::rules::ReductionError> {
150 let n = self.graph().num_vertices();
151 let q = self.num_colors().min(n);
154 let native_edges = self.graph().edges();
155 if native_edges.iter().any(|&(u, v)| u == v) {
156 return Ok(ReductionKColoringToBicliqueCover {
159 target: BicliqueCover::new(BipartiteGraph::new(1, 1, vec![(0, 0)]), 0),
160 num_vertices: n,
161 num_colors: q,
162 });
163 }
164
165 let mut source_edges: BTreeSet<(usize, usize)> = BTreeSet::new();
168 for (u, v) in native_edges {
169 let (a, b) = if u <= v { (u, v) } else { (v, u) };
170 source_edges.insert((a, b));
171 }
172 let has_source_edge = |u: usize, v: usize| -> bool {
173 if u == v {
174 return false;
175 }
176 let (a, b) = if u <= v { (u, v) } else { (v, u) };
177 source_edges.contains(&(a, b))
178 };
179
180 let a_left = |v: usize| -> usize { v };
184 let g_left = |v: usize| -> usize { n + v };
185 let b_right = |v: usize| -> usize { v };
186 let h_right = |v: usize| -> usize { n + v };
187
188 let mut edges: Vec<(usize, usize)> = Vec::new();
189
190 for v in 0..n {
192 edges.push((a_left(v), b_right(v)));
193 }
194
195 for u in 0..n {
197 for v in 0..n {
198 if u == v {
199 continue;
200 }
201 if !has_source_edge(u, v) {
202 edges.push((a_left(u), b_right(v)));
203 }
204 }
205 }
206
207 for v in 0..n {
209 edges.push((a_left(v), h_right(v)));
210 edges.push((g_left(v), h_right(v)));
211 }
212
213 for v in 0..n {
215 for w in 0..n {
216 if v == w {
217 continue;
218 }
219 if !has_source_edge(v, w) {
220 edges.push((g_left(v), b_right(w)));
221 }
222 }
223 }
224
225 let left_size = 2 * n;
226 let right_size = 2 * n;
227 let target = BicliqueCover::new(BipartiteGraph::new(left_size, right_size, edges), n + q);
228
229 Ok(ReductionKColoringToBicliqueCover {
230 target,
231 num_vertices: n,
232 num_colors: q,
233 })
234 }
235}
236
237#[cfg(any(test, feature = "example-db"))]
258pub(crate) fn forward_witness(
259 source: &KColoring<KN, SimpleGraph>,
260 coloring: &[usize],
261) -> Vec<Vec<bool>> {
262 let n = source.graph().num_vertices();
263 let q = source.num_colors().min(n);
264 let k = n + q;
265 let left_size = 2 * n;
266 let num_vertices = 4 * n;
267 let mut config = vec![vec![false; num_vertices]; k];
268
269 let set_member = |config: &mut Vec<Vec<bool>>, vertex: usize, biclique: usize| {
270 config[biclique][vertex] = true;
271 };
272
273 let mut source_edges: BTreeSet<(usize, usize)> = BTreeSet::new();
275 for (u, v) in source.graph().edges() {
276 let (a, b) = if u <= v { (u, v) } else { (v, u) };
277 source_edges.insert((a, b));
278 }
279 let has_source_edge = |u: usize, v: usize| -> bool {
280 if u == v {
281 return false;
282 }
283 let (a, b) = if u <= v { (u, v) } else { (v, u) };
284 source_edges.contains(&(a, b))
285 };
286
287 for v in 0..n {
289 let biclique = v;
290 set_member(&mut config, v, biclique);
292 set_member(&mut config, n + v, biclique);
293 set_member(&mut config, left_size + n + v, biclique); for w in 0..n {
296 if w != v && !has_source_edge(v, w) {
297 set_member(&mut config, left_size + w, biclique); }
299 }
300 }
301
302 let mut color_to_biclique: std::collections::HashMap<usize, usize> =
304 std::collections::HashMap::new();
305 for (v, &c) in coloring.iter().enumerate().take(n) {
306 let next_slot = color_to_biclique.len();
307 let slot = *color_to_biclique.entry(c).or_insert(next_slot);
308 let biclique = n + slot;
309 set_member(&mut config, v, biclique);
311 set_member(&mut config, left_size + v, biclique);
313 }
314
315 config
316}
317
318#[cfg(feature = "example-db")]
319pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
320 use crate::export::SolutionPair;
321
322 vec![crate::example_db::specs::RuleExampleSpec {
323 id: "kcoloring_to_bicliquecover",
324 build: || {
325 let source = KColoring::<KN, _>::with_k(SimpleGraph::new(2, vec![(0, 1)]), 2);
329 let coloring = vec![0usize, 1usize];
330 let target_config = forward_witness(&source, &coloring);
331 crate::example_db::specs::rule_example_with_witness::<_, BicliqueCover>(
332 source,
333 SolutionPair {
334 source_config: serde_json::json!(coloring),
335 target_config: serde_json::to_value(target_config)
336 .expect("solution serialization must succeed"),
337 },
338 )
339 },
340 }]
341}
342
343#[cfg(test)]
344#[path = "../unit_tests/rules/kcoloring_bicliquecover.rs"]
345mod tests;