problemreductions/rules/
minimumgraphbandwidth_ilp.rs1use crate::models::algebraic::{LinearConstraint, ObjectiveSense, ILP};
11use crate::models::graph::MinimumGraphBandwidth;
12use crate::reduction;
13use crate::rules::traits::{ReduceTo, ReductionResult};
14use crate::topology::{Graph, SimpleGraph};
15
16#[derive(Debug, Clone)]
23pub struct ReductionMGBToILP {
24 target: ILP<i64>,
25 num_vertices: usize,
26}
27
28impl ReductionResult for ReductionMGBToILP {
29 type Source = MinimumGraphBandwidth<SimpleGraph>;
30 type Target = ILP<i64>;
31
32 fn target_problem(&self) -> &ILP<i64> {
33 &self.target
34 }
35
36 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_solution(self.target_problem(), target_solution)?;
42
43 crate::rules::ilp_helpers::one_hot_decode_rows(
44 target_solution,
45 self.num_vertices,
46 self.num_vertices,
47 0,
48 )
49 }
50}
51
52#[reduction(
53 transform = exact {
54 num_vars = "num_vertices^2 + num_vertices + 1",
55 num_constraints = "2 * num_vertices + num_vertices^2 + num_vertices + num_vertices + 1 + 2 * num_edges",
56 },
57 unavailable = {
58 num_nonzeros = "the exact target parameter is not represented by this reduction's symbolic transform",
59 }
60)]
61impl ReduceTo<ILP<i64>> for MinimumGraphBandwidth<SimpleGraph> {
62 type Result = ReductionMGBToILP;
63
64 fn reduce_to(&self) -> Result<Self::Result, crate::rules::ReductionError> {
65 let n = self.num_vertices();
66 let graph = self.graph();
67 let edges = graph.edges();
68
69 let num_x = n * n;
70 let num_vars = num_x + n + 1;
71
72 let x_idx = |v: usize, p: usize| -> usize { v * n + p };
73 let pos_idx = |v: usize| -> usize { num_x + v };
74 let b_idx = num_x + n;
75
76 let mut constraints = Vec::new();
77 let n_i64 = Self::exact_i64(n, "encoding a vertex position")?;
78
79 for v in 0..n {
81 let terms: Vec<(usize, i64)> = (0..n).map(|p| (x_idx(v, p), 1)).collect();
82 constraints.push(LinearConstraint::eq(terms, 1));
83 }
84
85 for p in 0..n {
87 let terms: Vec<(usize, i64)> = (0..n).map(|v| (x_idx(v, p), 1)).collect();
88 constraints.push(LinearConstraint::eq(terms, 1));
89 }
90
91 for v in 0..n {
93 for p in 0..n {
94 constraints.push(LinearConstraint::le(vec![(x_idx(v, p), 1)], 1));
95 }
96 }
97
98 for v in 0..n {
100 let mut terms: Vec<(usize, i64)> = vec![(pos_idx(v), 1)];
101 for p in 0..n {
102 terms.push((
103 x_idx(v, p),
104 -Self::exact_i64(p, "encoding a vertex position")?,
105 ));
106 }
107 constraints.push(LinearConstraint::eq(terms, 0));
108 }
109
110 for v in 0..n {
112 constraints.push(LinearConstraint::le(vec![(pos_idx(v), 1)], n_i64 - 1));
113 }
114
115 constraints.push(LinearConstraint::le(vec![(b_idx, 1)], n_i64 - 1));
117
118 for &(u, v) in edges.iter() {
122 constraints.push(LinearConstraint::le(
123 vec![(pos_idx(u), 1), (pos_idx(v), -1), (b_idx, -1)],
124 0,
125 ));
126 constraints.push(LinearConstraint::le(
127 vec![(pos_idx(v), 1), (pos_idx(u), -1), (b_idx, -1)],
128 0,
129 ));
130 }
131
132 let objective = vec![(b_idx, 1)];
134 let target = ILP::new(num_vars, constraints, objective, ObjectiveSense::Minimize)
135 .map_err(Self::target_construction)?;
136
137 Ok(ReductionMGBToILP {
138 target,
139 num_vertices: n,
140 })
141 }
142}
143
144#[cfg(feature = "example-db")]
145pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
146 vec![crate::example_db::specs::RuleExampleSpec {
147 id: "minimumgraphbandwidth_to_ilp",
148 build: || {
149 let source =
151 MinimumGraphBandwidth::new(SimpleGraph::new(4, vec![(0, 1), (0, 2), (0, 3)]));
152 crate::example_db::specs::rule_example_via_ilp::<_, i64>(source)
153 },
154 }]
155}
156
157#[cfg(test)]
158#[path = "../unit_tests/rules/minimumgraphbandwidth_ilp.rs"]
159mod tests;