problemreductions/rules/
maximumedgeweightedkclique_ilp.rs1use crate::models::algebraic::{LinearConstraint, ObjectiveSense, ILP};
26use crate::models::graph::MaximumEdgeWeightedKClique;
27use crate::reduction;
28use crate::rules::ilp_helpers::mccormick_product;
29use crate::rules::traits::{ReduceTo, ReductionResult};
30use crate::topology::Graph;
31use crate::types::WeightElement;
32use crate::variant::VariantParam;
33use std::marker::PhantomData;
34
35#[derive(Debug, Clone)]
42pub struct ReductionMaximumEdgeWeightedKCliqueToILP<W> {
43 target: ILP<bool>,
44 num_vertices: usize,
45 _marker: PhantomData<W>,
46}
47
48impl<W> ReductionResult for ReductionMaximumEdgeWeightedKCliqueToILP<W>
49where
50 W: WeightElement + VariantParam,
51{
52 type Source = MaximumEdgeWeightedKClique<W>;
53 type Target = ILP<bool>;
54
55 fn target_problem(&self) -> &ILP<bool> {
56 &self.target
57 }
58
59 fn extract_solution(&self, target_solution: &[usize]) -> Vec<usize> {
62 target_solution[..self.num_vertices].to_vec()
63 }
64}
65
66fn build_reduction<W>(
67 src: &MaximumEdgeWeightedKClique<W>,
68 objective_coefficients: Vec<f64>,
69) -> ReductionMaximumEdgeWeightedKCliqueToILP<W>
70where
71 W: WeightElement + VariantParam,
72{
73 let n = src.num_vertices();
74 let edges = src.graph().edges();
75 let m = edges.len();
76 debug_assert_eq!(objective_coefficients.len(), m);
77
78 let num_vars = n + m;
79 let x_idx = |v: usize| -> usize { v };
80 let y_idx = |e: usize| -> usize { n + e };
81
82 let mut constraints: Vec<LinearConstraint> = Vec::new();
83
84 let cardinality_terms: Vec<(usize, f64)> = (0..n).map(|v| (x_idx(v), 1.0)).collect();
86 constraints.push(LinearConstraint::eq(cardinality_terms, src.k() as f64));
87
88 for u in 0..n {
90 for v in (u + 1)..n {
91 if !src.graph().has_edge(u, v) {
92 constraints.push(LinearConstraint::le(
93 vec![(x_idx(u), 1.0), (x_idx(v), 1.0)],
94 1.0,
95 ));
96 }
97 }
98 }
99
100 for (e, &(u, v)) in edges.iter().enumerate() {
102 constraints.extend(mccormick_product(y_idx(e), x_idx(u), x_idx(v)));
103 }
104
105 let objective: Vec<(usize, f64)> = objective_coefficients
107 .into_iter()
108 .enumerate()
109 .map(|(e, w)| (y_idx(e), w))
110 .collect();
111
112 let target = ILP::new(num_vars, constraints, objective, ObjectiveSense::Maximize);
113
114 ReductionMaximumEdgeWeightedKCliqueToILP {
115 target,
116 num_vertices: n,
117 _marker: PhantomData,
118 }
119}
120
121#[reduction(
122 overhead = {
123 num_vars = "num_vertices + num_edges",
124 num_constraints = "1 + num_vertices * (num_vertices - 1) / 2 + 2 * num_edges",
125 }
126)]
127impl ReduceTo<ILP<bool>> for MaximumEdgeWeightedKClique<i32> {
128 type Result = ReductionMaximumEdgeWeightedKCliqueToILP<i32>;
129
130 fn reduce_to(&self) -> Self::Result {
131 let coefficients: Vec<f64> = self.edge_weights().iter().map(|w| *w as f64).collect();
132 build_reduction(self, coefficients)
133 }
134}
135
136#[reduction(
137 overhead = {
138 num_vars = "num_vertices + num_edges",
139 num_constraints = "1 + num_vertices * (num_vertices - 1) / 2 + 2 * num_edges",
140 }
141)]
142impl ReduceTo<ILP<bool>> for MaximumEdgeWeightedKClique<f64> {
143 type Result = ReductionMaximumEdgeWeightedKCliqueToILP<f64>;
144
145 fn reduce_to(&self) -> Self::Result {
146 let coefficients: Vec<f64> = self.edge_weights().to_vec();
147 build_reduction(self, coefficients)
148 }
149}
150
151#[cfg(feature = "example-db")]
152pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
153 use crate::topology::SimpleGraph;
154 vec![
155 crate::example_db::specs::RuleExampleSpec {
156 id: "maximumedgeweightedkclique_i32_to_ilp",
157 build: || {
158 let source = MaximumEdgeWeightedKClique::<i32>::new(
161 SimpleGraph::new(4, vec![(0, 1), (0, 2), (1, 2), (0, 3), (1, 3)]),
162 vec![5, 4, -1, 1, 0],
163 3,
164 );
165 crate::example_db::specs::rule_example_via_ilp::<_, bool>(source)
166 },
167 },
168 crate::example_db::specs::RuleExampleSpec {
169 id: "maximumedgeweightedkclique_f64_to_ilp",
170 build: || {
171 let source = MaximumEdgeWeightedKClique::<f64>::new(
172 SimpleGraph::new(4, vec![(0, 1), (0, 2), (1, 2), (0, 3), (1, 3)]),
173 vec![5.0, 4.0, -1.0, 1.0, 0.0],
174 3,
175 );
176 crate::example_db::specs::rule_example_via_ilp::<_, bool>(source)
177 },
178 },
179 ]
180}
181
182#[cfg(test)]
183#[path = "../unit_tests/rules/maximumedgeweightedkclique_ilp.rs"]
184mod tests;