problemreductions/rules/
kclique_balancedcompletebipartitesubgraph.rs1use crate::models::graph::{BalancedCompleteBipartiteSubgraph, KClique};
9use crate::reduction;
10use crate::rules::traits::{ReduceTo, ReductionResult};
11use crate::topology::{BipartiteGraph, Graph, SimpleGraph};
12
13#[derive(Debug, Clone)]
18pub struct ReductionKCliqueToBCBS {
19 target: BalancedCompleteBipartiteSubgraph,
20 num_original_vertices: usize,
22}
23
24impl ReductionResult for ReductionKCliqueToBCBS {
25 type Source = KClique<SimpleGraph>;
26 type Target = BalancedCompleteBipartiteSubgraph;
27
28 fn target_problem(&self) -> &BalancedCompleteBipartiteSubgraph {
29 &self.target
30 }
31
32 fn extract_solution(
38 &self,
39 target_solution: &<Self::Target as crate::traits::Problem>::Solution,
40 ) -> crate::rules::ExtractionResult<<Self::Source as crate::traits::Problem>::Solution> {
41 crate::rules::traits::validate_target_witness(
42 self.target_problem(),
43 target_solution,
44 |value| value.0,
45 "target witness is not satisfying",
46 )?;
47
48 Ok({
49 (0..self.num_original_vertices)
50 .map(|v| !target_solution[v])
51 .collect()
52 })
53 }
54}
55
56#[crate::aggregate_reduction(identity)]
57impl crate::rules::AggregateReductionResult for ReductionKCliqueToBCBS {}
58
59#[reduction(transform = upper_bound {
60 left_size = "num_vertices + k * (k - 1) / 2",
61 right_size = "num_edges + num_vertices - k",
62 k = "num_vertices + k * (k - 1) / 2 - k",
63 num_vertices = "2 * num_vertices + num_edges + k * (k - 1) / 2 - k",
64})]
65impl ReduceTo<BalancedCompleteBipartiteSubgraph> for KClique<SimpleGraph> {
66 type Result = ReductionKCliqueToBCBS;
67
68 fn reduce_to(&self) -> Result<Self::Result, crate::rules::ReductionError> {
69 let n = self.num_vertices();
70 let k = self.k();
71 let edges: Vec<(usize, usize)> = self
73 .graph()
74 .edges()
75 .into_iter()
76 .filter(|&(u, v)| u != v)
77 .map(|(u, v)| (u.min(v), u.max(v)))
78 .collect::<std::collections::BTreeSet<_>>()
79 .into_iter()
80 .collect();
81 let m = edges.len();
82
83 let ck2 = k * (k - 1) / 2;
85
86 let left_size = n + ck2;
88
89 let num_padding = n - k;
91 let right_size = m + num_padding;
92
93 let target_k = left_size - k;
95
96 let mut bip_edges = Vec::new();
98
99 for v in 0..left_size {
100 for (j, &(u, w)) in edges.iter().enumerate() {
102 if v != u && v != w {
103 bip_edges.push((v, j));
106 }
107 }
108
109 for p in 0..num_padding {
111 bip_edges.push((v, m + p));
112 }
113 }
114
115 let graph = BipartiteGraph::new(left_size, right_size, bip_edges);
116 let target = BalancedCompleteBipartiteSubgraph::new(graph, target_k);
117
118 Ok(ReductionKCliqueToBCBS {
119 target,
120 num_original_vertices: n,
121 })
122 }
123}
124
125#[cfg(feature = "example-db")]
126pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
127 use crate::export::SolutionPair;
128
129 vec![crate::example_db::specs::RuleExampleSpec {
130 id: "kclique_to_balancedcompletebipartitesubgraph",
131 build: || {
132 let source = KClique::new(SimpleGraph::new(4, vec![(0, 1), (0, 2), (1, 2), (2, 3)]), 3);
135 crate::example_db::specs::rule_example_with_witness::<
146 _,
147 BalancedCompleteBipartiteSubgraph,
148 >(
149 source,
150 SolutionPair {
151 source_config: serde_json::json!(vec![true, true, true, false]),
152 target_config: serde_json::json!(vec![
153 false, false, false, true, true, true, true, true, true, true, false, true
154 ]),
155 },
156 )
157 },
158 }]
159}
160
161#[cfg(test)]
162#[path = "../unit_tests/rules/kclique_balancedcompletebipartitesubgraph.rs"]
163mod tests;