problemreductions/rules/
directedhamiltonianpath_ilp.rs1use crate::models::algebraic::{LinearConstraint, ObjectiveSense, ILP};
10use crate::models::graph::DirectedHamiltonianPath;
11use crate::reduction;
12use crate::rules::ilp_helpers::{
13 one_hot_assignment_constraints, one_hot_decode, permutation_to_lehmer,
14};
15use crate::rules::traits::{ReduceTo, ReductionResult};
16
17#[derive(Debug, Clone)]
22pub struct ReductionDirectedHamiltonianPathToILP {
23 target: ILP<bool>,
24 num_vertices: usize,
25}
26
27impl ReductionResult for ReductionDirectedHamiltonianPathToILP {
28 type Source = DirectedHamiltonianPath;
29 type Target = ILP<bool>;
30
31 fn target_problem(&self) -> &ILP<bool> {
32 &self.target
33 }
34
35 fn extract_solution(&self, target_solution: &[usize]) -> Vec<usize> {
36 let n = self.num_vertices;
37 let perm = one_hot_decode(target_solution, n, n, 0);
39 permutation_to_lehmer(&perm)
40 }
41}
42
43#[reduction(
44 overhead = {
45 num_vars = "num_vertices^2",
46 num_constraints = "3 * num_vertices + (num_vertices - 1) * (num_vertices^2 - num_arcs)",
47 }
48)]
49impl ReduceTo<ILP<bool>> for DirectedHamiltonianPath {
50 type Result = ReductionDirectedHamiltonianPathToILP;
51
52 fn reduce_to(&self) -> Self::Result {
53 let n = self.num_vertices();
54 let arcs = self.graph().arcs();
55
56 let mut arc_set = std::collections::HashSet::new();
58 for (u, v) in &arcs {
59 arc_set.insert((*u, *v));
60 }
61
62 let x_idx = |v: usize, k: usize| -> usize { v * n + k };
63
64 let mut constraints = Vec::new();
65
66 constraints.extend(one_hot_assignment_constraints(n, n, 0));
69 for k in 0..n {
74 let terms: Vec<(usize, f64)> = (0..n).map(|v| (x_idx(v, k), 1.0)).collect();
75 constraints.push(LinearConstraint::ge(terms, 1.0));
76 }
77
78 if n >= 2 {
81 for k in 0..n - 1 {
82 for v in 0..n {
83 for w in 0..n {
84 if !arc_set.contains(&(v, w)) {
85 constraints.push(LinearConstraint::le(
86 vec![(x_idx(v, k), 1.0), (x_idx(w, k + 1), 1.0)],
87 1.0,
88 ));
89 }
90 }
91 }
92 }
93 }
94
95 let target = ILP::new(n * n, constraints, vec![], ObjectiveSense::Minimize);
97
98 ReductionDirectedHamiltonianPathToILP {
99 target,
100 num_vertices: n,
101 }
102 }
103}
104
105#[cfg(feature = "example-db")]
106pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
107 vec![crate::example_db::specs::RuleExampleSpec {
108 id: "directedhamiltonianpath_to_ilp",
109 build: || {
110 let source = DirectedHamiltonianPath::new(crate::topology::DirectedGraph::new(
112 4,
113 vec![(0, 1), (1, 2), (2, 3)],
114 ));
115 crate::example_db::specs::rule_example_via_ilp::<_, bool>(source)
116 },
117 }]
118}
119
120#[cfg(test)]
121#[path = "../unit_tests/rules/directedhamiltonianpath_ilp.rs"]
122mod tests;