problemreductions/rules/
minimumvertexcover_minimumfeedbackarcset.rs1use crate::models::graph::{MinimumFeedbackArcSet, MinimumVertexCover};
12use crate::reduction;
13use crate::rules::traits::{ReduceTo, ReductionResult};
14use crate::topology::{DirectedGraph, Graph, SimpleGraph};
15
16#[derive(Debug, Clone)]
18pub struct ReductionVCToFAS {
19 target: MinimumFeedbackArcSet<i32>,
20 num_source_vertices: usize,
22}
23
24impl ReductionResult for ReductionVCToFAS {
25 type Source = MinimumVertexCover<SimpleGraph, i32>;
26 type Target = MinimumFeedbackArcSet<i32>;
27
28 fn target_problem(&self) -> &Self::Target {
29 &self.target
30 }
31
32 fn extract_solution(&self, target_solution: &[usize]) -> Vec<usize> {
35 target_solution[..self.num_source_vertices].to_vec()
36 }
37}
38
39#[reduction(
40 overhead = {
41 num_vertices = "2 * num_vertices",
42 num_arcs = "num_vertices + 2 * num_edges",
43 }
44)]
45impl ReduceTo<MinimumFeedbackArcSet<i32>> for MinimumVertexCover<SimpleGraph, i32> {
46 type Result = ReductionVCToFAS;
47
48 fn reduce_to(&self) -> Self::Result {
49 let n = self.graph().num_vertices();
50 let edges = self.graph().edges();
51
52 let weight_sum: i32 = self.weights().iter().sum::<i32>();
57 let big_m: i32 = weight_sum
58 .checked_add(1)
59 .expect("penalty M = 1 + sum(weights) overflows i32");
60
61 let mut arcs = Vec::with_capacity(n + 2 * edges.len());
62 let mut weights = Vec::with_capacity(n + 2 * edges.len());
63
64 for v in 0..n {
66 arcs.push((v, n + v)); weights.push(self.weights()[v]);
68 }
69
70 for (u, v) in &edges {
72 arcs.push((n + u, *v)); weights.push(big_m);
74 arcs.push((n + v, *u)); weights.push(big_m);
76 }
77
78 let graph = DirectedGraph::new(2 * n, arcs);
79 let target = MinimumFeedbackArcSet::new(graph, weights);
80
81 ReductionVCToFAS {
82 target,
83 num_source_vertices: n,
84 }
85 }
86}
87
88#[cfg(feature = "example-db")]
89pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
90 use crate::export::SolutionPair;
91 use crate::solvers::BruteForce;
92
93 vec![crate::example_db::specs::RuleExampleSpec {
94 id: "minimumvertexcover_to_minimumfeedbackarcset",
95 build: || {
96 let source = MinimumVertexCover::new(
99 SimpleGraph::new(3, vec![(0, 1), (1, 2), (2, 0)]),
100 vec![1i32; 3],
101 );
102 let reduction = ReduceTo::<MinimumFeedbackArcSet<i32>>::reduce_to(&source);
103 let target = reduction.target_problem();
104
105 let target_witness = BruteForce::new()
106 .find_witness(target)
107 .expect("target should have an optimum");
108 let source_witness = reduction.extract_solution(&target_witness);
109
110 crate::example_db::specs::rule_example_with_witness::<_, MinimumFeedbackArcSet<i32>>(
111 source,
112 SolutionPair {
113 source_config: source_witness,
114 target_config: target_witness,
115 },
116 )
117 },
118 }]
119}
120
121#[cfg(test)]
122#[path = "../unit_tests/rules/minimumvertexcover_minimumfeedbackarcset.rs"]
123mod tests;