problemreductions/rules/
minimumfeedbackvertexset_ilp.rs1use crate::models::algebraic::{LinearConstraint, ObjectiveSense, ILP};
10use crate::models::graph::MinimumFeedbackVertexSet;
11use crate::reduction;
12use crate::rules::traits::{ReduceTo, ReductionResult};
13
14#[derive(Debug, Clone)]
23pub struct ReductionMFVSToILP {
24 target: ILP<i32>,
25 num_vertices: usize,
27}
28
29impl ReductionResult for ReductionMFVSToILP {
30 type Source = MinimumFeedbackVertexSet<i32>;
31 type Target = ILP<i32>;
32
33 fn target_problem(&self) -> &ILP<i32> {
34 &self.target
35 }
36
37 fn extract_solution(&self, target_solution: &[usize]) -> Vec<usize> {
42 target_solution[..self.num_vertices].to_vec()
43 }
44}
45
46#[reduction(
47 overhead = {
48 num_vars = "2 * num_vertices",
49 num_constraints = "num_arcs + 2 * num_vertices",
50 }
51)]
52impl ReduceTo<ILP<i32>> for MinimumFeedbackVertexSet<i32> {
53 type Result = ReductionMFVSToILP;
54
55 fn reduce_to(&self) -> Self::Result {
56 let n = self.graph().num_vertices();
57 let arcs = self.graph().arcs();
58 let num_vars = 2 * n;
59
60 let mut constraints = Vec::new();
65
66 for i in 0..n {
68 constraints.push(LinearConstraint::le(vec![(i, 1.0)], 1.0));
69 }
70
71 for i in 0..n {
73 constraints.push(LinearConstraint::le(vec![(n + i, 1.0)], (n - 1) as f64));
74 }
75
76 let n_f64 = n as f64;
80 for &(u, v) in &arcs {
81 let terms = vec![
82 (n + v, 1.0), (n + u, -1.0), (u, n_f64), (v, n_f64), ];
87 constraints.push(LinearConstraint::ge(terms, 1.0));
88 }
89
90 let objective: Vec<(usize, f64)> = self
92 .weights()
93 .iter()
94 .enumerate()
95 .map(|(i, &w)| (i, w as f64))
96 .collect();
97
98 let target = ILP::new(num_vars, constraints, objective, ObjectiveSense::Minimize);
99
100 ReductionMFVSToILP {
101 target,
102 num_vertices: n,
103 }
104 }
105}
106
107#[cfg(feature = "example-db")]
108pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
109 use crate::topology::DirectedGraph;
110
111 vec![crate::example_db::specs::RuleExampleSpec {
112 id: "minimumfeedbackvertexset_to_ilp",
113 build: || {
114 let graph = DirectedGraph::new(3, vec![(0, 1), (1, 2), (2, 0)]);
116 let source = MinimumFeedbackVertexSet::new(graph, vec![1i32; 3]);
117 crate::example_db::specs::rule_example_via_ilp::<_, i32>(source)
118 },
119 }]
120}
121
122#[cfg(test)]
123#[path = "../unit_tests/rules/minimumfeedbackvertexset_ilp.rs"]
124mod tests;