problemreductions/rules/
minimummaximalmatching_ilp.rs1use crate::models::algebraic::{LinearConstraint, ObjectiveSense, ILP};
11use crate::models::graph::MinimumMaximalMatching;
12use crate::reduction;
13use crate::rules::traits::{ReduceTo, ReductionResult};
14use crate::topology::{Graph, SimpleGraph};
15
16#[derive(Debug, Clone)]
25pub struct ReductionMMMToILP {
26 target: ILP<bool>,
27}
28
29impl ReductionResult for ReductionMMMToILP {
30 type Source = MinimumMaximalMatching<SimpleGraph>;
31 type Target = ILP<bool>;
32
33 fn target_problem(&self) -> &ILP<bool> {
34 &self.target
35 }
36
37 fn extract_solution(
42 &self,
43 target_solution: &<Self::Target as crate::traits::Problem>::Solution,
44 ) -> crate::rules::ExtractionResult<<Self::Source as crate::traits::Problem>::Solution> {
45 crate::rules::traits::validate_target_solution(self.target_problem(), target_solution)?;
46
47 Ok(target_solution.iter().map(|&value| value == 1).collect())
48 }
49}
50
51#[reduction(transform = {
55 exact {
56 num_vars = "num_edges",
57 },
58 upper_bound {
59 max_constraint_magnitude_bits = "2",
60 num_constraints = "num_vertices + num_edges",
61 num_nonzeros = "2 * num_edges + num_edges^2",
62 },
63})]
64impl ReduceTo<ILP<bool>> for MinimumMaximalMatching<SimpleGraph> {
65 type Result = ReductionMMMToILP;
66
67 fn reduce_to(&self) -> Result<Self::Result, crate::rules::ReductionError> {
68 let edges = self.graph().edges();
69 let num_vars = edges.len();
70 let mut constraints = Vec::new();
71
72 let n = self.graph().num_vertices();
75 let mut v2e: Vec<Vec<usize>> = vec![Vec::new(); n];
76 for (idx, &(u, v)) in edges.iter().enumerate() {
77 v2e[u].push(idx);
78 v2e[v].push(idx);
79 }
80 for incident in &v2e {
81 if !incident.is_empty() {
82 let terms: Vec<(usize, i64)> = incident.iter().map(|&e| (e, 1)).collect();
83 constraints.push(LinearConstraint::le(terms, 1));
84 }
85 }
86
87 for (j, &(uj, vj)) in edges.iter().enumerate() {
91 let mut neighbors: Vec<usize> = vec![j];
93 for &i in v2e[uj].iter().chain(v2e[vj].iter()) {
94 if i != j && !neighbors.contains(&i) {
95 neighbors.push(i);
96 }
97 }
98 let terms: Vec<(usize, i64)> = neighbors.iter().map(|&i| (i, 1)).collect();
99 constraints.push(LinearConstraint::ge(terms, 1));
100 }
101
102 let objective: Vec<(usize, i64)> = (0..num_vars).map(|i| (i, 1)).collect();
104
105 let target = ILP::new(num_vars, constraints, objective, ObjectiveSense::Minimize)
106 .map_err(Self::target_construction)?;
107 Ok(ReductionMMMToILP { target })
108 }
109}
110
111#[cfg(feature = "example-db")]
112pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
113 vec![crate::example_db::specs::RuleExampleSpec {
114 id: "minimummaximalmatching_to_ilp",
115 build: || {
116 let source = MinimumMaximalMatching::new(SimpleGraph::new(
118 6,
119 vec![(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)],
120 ));
121 crate::example_db::specs::rule_example_via_ilp::<_, bool>(source)
122 },
123 }]
124}
125
126#[cfg(test)]
127#[path = "../unit_tests/rules/minimummaximalmatching_ilp.rs"]
128mod tests;