problemreductions/rules/
isomorphicspanningtree_ilp.rs1use crate::models::algebraic::{LinearConstraint, ObjectiveSense, ILP};
7use crate::models::graph::IsomorphicSpanningTree;
8use crate::reduction;
9use crate::rules::traits::{ReduceTo, ReductionResult};
10use crate::topology::{Graph, SimpleGraph};
11
12#[derive(Debug, Clone)]
13pub struct ReductionISTToILP {
14 target: ILP<bool>,
15 n: usize,
16}
17
18impl ReductionResult for ReductionISTToILP {
19 type Source = IsomorphicSpanningTree<SimpleGraph>;
20 type Target = ILP<bool>;
21
22 fn target_problem(&self) -> &ILP<bool> {
23 &self.target
24 }
25
26 fn extract_solution(&self, target_solution: &[usize]) -> Vec<usize> {
28 let n = self.n;
29 (0..n)
30 .map(|u| {
31 (0..n)
32 .find(|&v| target_solution[u * n + v] == 1)
33 .unwrap_or(0)
34 })
35 .collect()
36 }
37}
38
39#[reduction(
40 overhead = {
41 num_vars = "num_vertices * num_vertices",
42 num_constraints = "2 * num_vertices + 2 * (num_vertices - 1) * num_vertices * num_vertices",
43 }
44)]
45impl ReduceTo<ILP<bool>> for IsomorphicSpanningTree<SimpleGraph> {
46 type Result = ReductionISTToILP;
47
48 fn reduce_to(&self) -> Self::Result {
49 let n = self.num_vertices();
50 let num_vars = n * n;
51
52 let mut constraints = Vec::new();
53
54 for u in 0..n {
57 let terms: Vec<(usize, f64)> = (0..n).map(|v| (u * n + v, 1.0)).collect();
58 constraints.push(LinearConstraint::eq(terms, 1.0));
59 }
60
61 for v in 0..n {
64 let terms: Vec<(usize, f64)> = (0..n).map(|u| (u * n + v, 1.0)).collect();
65 constraints.push(LinearConstraint::eq(terms, 1.0));
66 }
67
68 for (u, w) in self.tree().edges() {
72 for v in 0..n {
73 for z in 0..n {
74 if v != z && !self.graph().has_edge(v, z) {
75 constraints.push(LinearConstraint::le(
76 vec![(u * n + v, 1.0), (w * n + z, 1.0)],
77 1.0,
78 ));
79 }
80 }
81 }
82 }
83
84 let target = ILP::new(num_vars, constraints, vec![], ObjectiveSense::Minimize);
85 ReductionISTToILP { target, n }
86 }
87}
88
89#[cfg(feature = "example-db")]
90pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
91 use crate::export::SolutionPair;
92 use crate::topology::SimpleGraph;
93 vec![crate::example_db::specs::RuleExampleSpec {
94 id: "isomorphicspanningtree_to_ilp",
95 build: || {
96 let source = IsomorphicSpanningTree::new(
98 SimpleGraph::new(4, vec![(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)]),
99 SimpleGraph::new(4, vec![(0, 1), (0, 2), (0, 3)]),
100 );
101 crate::example_db::specs::rule_example_with_witness::<_, ILP<bool>>(
103 source,
104 SolutionPair {
105 source_config: vec![0, 1, 2, 3],
106 target_config: vec![1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1],
108 },
109 )
110 },
111 }]
112}
113
114#[cfg(test)]
115#[path = "../unit_tests/rules/isomorphicspanningtree_ilp.rs"]
116mod tests;