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 let value =
76 crate::rules::traits::validate_target_solution(self.target_problem(), target_solution)?;
77 if value.0.is_none() {
78 return Err(crate::rules::ExtractionError::invalid(
79 "target configuration is not a biclique cover",
80 ));
81 }
82
83 Ok({
84 let n = self.num_vertices;
85 let k = self.target.k();
86 let left_size = 2 * n;
87
88 let mut diagonal_biclique = Vec::with_capacity(n);
91 for v in 0..n {
92 let a_v = v;
93 let b_v = left_size + v;
94 let biclique = (0..k)
95 .find(|&r| target_solution[r][a_v] && target_solution[r][b_v])
96 .ok_or_else(|| {
97 crate::rules::ExtractionError::invalid(format!(
98 "target cover leaves diagonal gadget edge {v} uncovered"
99 ))
100 })?;
101 diagonal_biclique.push(biclique);
102 }
103
104 let mut color_of_biclique: std::collections::HashMap<usize, usize> =
106 std::collections::HashMap::new();
107 let mut coloring = Vec::with_capacity(n);
108 for biclique in diagonal_biclique {
109 let next_color = color_of_biclique.len();
110 let color = *color_of_biclique.entry(biclique).or_insert(next_color);
111 if color >= self.num_colors {
112 return Err(crate::rules::ExtractionError::invalid(format!(
113 "target cover uses more than {} diagonal bicliques",
114 self.num_colors
115 )));
116 }
117 coloring.push(color);
118 }
119 coloring
120 })
121 }
122}
123
124#[reduction(
125 transform = upper_bound {
126 left_size = "2 * num_vertices + 1",
127 num_vertices = "4 * num_vertices + 2",
128 num_edges = "2 * num_vertices^2 + num_vertices + 1",
129 rank = "2 * num_vertices",
130 right_size = "2 * num_vertices + 1",
131 }
132)]
133impl ReduceTo<BicliqueCover> for KColoring<KN, SimpleGraph> {
134 type Result = ReductionKColoringToBicliqueCover;
135
136 fn reduce_to(&self) -> Result<Self::Result, crate::rules::ReductionError> {
137 let n = self.graph().num_vertices();
138 let q = self.num_colors().min(n);
141 let native_edges = self.graph().edges();
142 if native_edges.iter().any(|&(u, v)| u == v) {
143 return Ok(ReductionKColoringToBicliqueCover {
146 target: BicliqueCover::new(BipartiteGraph::new(1, 1, vec![(0, 0)]), 0),
147 num_vertices: n,
148 num_colors: q,
149 });
150 }
151
152 let mut source_edges: BTreeSet<(usize, usize)> = BTreeSet::new();
155 for (u, v) in native_edges {
156 let (a, b) = if u <= v { (u, v) } else { (v, u) };
157 source_edges.insert((a, b));
158 }
159 let has_source_edge = |u: usize, v: usize| -> bool {
160 if u == v {
161 return false;
162 }
163 let (a, b) = if u <= v { (u, v) } else { (v, u) };
164 source_edges.contains(&(a, b))
165 };
166
167 let a_left = |v: usize| -> usize { v };
171 let g_left = |v: usize| -> usize { n + v };
172 let b_right = |v: usize| -> usize { v };
173 let h_right = |v: usize| -> usize { n + v };
174
175 let mut edges: Vec<(usize, usize)> = Vec::new();
176
177 for v in 0..n {
179 edges.push((a_left(v), b_right(v)));
180 }
181
182 for u in 0..n {
184 for v in 0..n {
185 if u == v {
186 continue;
187 }
188 if !has_source_edge(u, v) {
189 edges.push((a_left(u), b_right(v)));
190 }
191 }
192 }
193
194 for v in 0..n {
196 edges.push((a_left(v), h_right(v)));
197 edges.push((g_left(v), h_right(v)));
198 }
199
200 for v in 0..n {
202 for w in 0..n {
203 if v == w {
204 continue;
205 }
206 if !has_source_edge(v, w) {
207 edges.push((g_left(v), b_right(w)));
208 }
209 }
210 }
211
212 let left_size = 2 * n;
213 let right_size = 2 * n;
214 let target = BicliqueCover::new(BipartiteGraph::new(left_size, right_size, edges), n + q);
215
216 Ok(ReductionKColoringToBicliqueCover {
217 target,
218 num_vertices: n,
219 num_colors: q,
220 })
221 }
222}
223
224#[cfg(any(test, feature = "example-db"))]
245pub(crate) fn forward_witness(
246 source: &KColoring<KN, SimpleGraph>,
247 coloring: &[usize],
248) -> Vec<Vec<bool>> {
249 let n = source.graph().num_vertices();
250 let q = source.num_colors().min(n);
251 let k = n + q;
252 let left_size = 2 * n;
253 let num_vertices = 4 * n;
254 let mut config = vec![vec![false; num_vertices]; k];
255
256 let set_member = |config: &mut Vec<Vec<bool>>, vertex: usize, biclique: usize| {
257 config[biclique][vertex] = true;
258 };
259
260 let mut source_edges: BTreeSet<(usize, usize)> = BTreeSet::new();
262 for (u, v) in source.graph().edges() {
263 let (a, b) = if u <= v { (u, v) } else { (v, u) };
264 source_edges.insert((a, b));
265 }
266 let has_source_edge = |u: usize, v: usize| -> bool {
267 if u == v {
268 return false;
269 }
270 let (a, b) = if u <= v { (u, v) } else { (v, u) };
271 source_edges.contains(&(a, b))
272 };
273
274 for v in 0..n {
276 let biclique = v;
277 set_member(&mut config, v, biclique);
279 set_member(&mut config, n + v, biclique);
280 set_member(&mut config, left_size + n + v, biclique); for w in 0..n {
283 if w != v && !has_source_edge(v, w) {
284 set_member(&mut config, left_size + w, biclique); }
286 }
287 }
288
289 let mut color_to_biclique: std::collections::HashMap<usize, usize> =
291 std::collections::HashMap::new();
292 for (v, &c) in coloring.iter().enumerate().take(n) {
293 let next_slot = color_to_biclique.len();
294 let slot = *color_to_biclique.entry(c).or_insert(next_slot);
295 let biclique = n + slot;
296 set_member(&mut config, v, biclique);
298 set_member(&mut config, left_size + v, biclique);
300 }
301
302 config
303}
304
305#[cfg(feature = "example-db")]
306pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
307 use crate::export::SolutionPair;
308
309 vec![crate::example_db::specs::RuleExampleSpec {
310 id: "kcoloring_to_bicliquecover",
311 build: || {
312 let source = KColoring::<KN, _>::with_k(SimpleGraph::new(2, vec![(0, 1)]), 2);
316 let coloring = vec![0usize, 1usize];
317 let target_config = forward_witness(&source, &coloring);
318 crate::example_db::specs::rule_example_with_witness::<_, BicliqueCover>(
319 source,
320 SolutionPair {
321 source_config: serde_json::json!(coloring),
322 target_config: serde_json::to_value(target_config)
323 .expect("solution serialization must succeed"),
324 },
325 )
326 },
327 }]
328}
329
330#[cfg(test)]
331#[path = "../unit_tests/rules/kcoloring_bicliquecover.rs"]
332mod tests;