problemreductions/rules/
minimumfeedbackarcset_maximumlikelihoodranking.rs1use crate::models::graph::MinimumFeedbackArcSet;
9use crate::models::misc::MaximumLikelihoodRanking;
10use crate::reduction;
11use crate::rules::traits::{ReduceTo, ReductionResult};
12
13#[allow(clippy::needless_range_loop)]
14fn build_skew_symmetric_matrix(problem: &MinimumFeedbackArcSet<i32>) -> Vec<Vec<i32>> {
15 let n = problem.num_vertices();
16 let graph = problem.graph();
17 let mut matrix = vec![vec![0i32; n]; n];
18
19 for i in 0..n {
20 for j in (i + 1)..n {
21 let ij = graph.has_arc(i, j);
22 let ji = graph.has_arc(j, i);
23 if ij && !ji {
24 matrix[i][j] = 1;
25 matrix[j][i] = -1;
26 } else if ji && !ij {
27 matrix[i][j] = -1;
28 matrix[j][i] = 1;
29 }
30 }
31 }
32
33 matrix
34}
35
36#[derive(Debug, Clone)]
38pub struct ReductionFASToMLR {
39 target: MaximumLikelihoodRanking,
40 source_arcs: Vec<(usize, usize)>,
41}
42
43impl ReductionResult for ReductionFASToMLR {
44 type Source = MinimumFeedbackArcSet<i32>;
45 type Target = MaximumLikelihoodRanking;
46
47 fn target_problem(&self) -> &Self::Target {
48 &self.target
49 }
50
51 fn extract_solution(&self, target_solution: &[usize]) -> Vec<usize> {
52 self.source_arcs
53 .iter()
54 .map(|&(u, v)| usize::from(target_solution[u] > target_solution[v]))
55 .collect()
56 }
57}
58
59#[reduction(
60 overhead = {
61 num_items = "num_vertices",
62 }
63)]
64impl ReduceTo<MaximumLikelihoodRanking> for MinimumFeedbackArcSet<i32> {
65 type Result = ReductionFASToMLR;
66
67 fn reduce_to(&self) -> Self::Result {
68 assert!(
69 self.weights().iter().all(|&weight| weight == 1),
70 "MinimumFeedbackArcSet -> MaximumLikelihoodRanking requires unit arc weights"
71 );
72
73 ReductionFASToMLR {
74 target: MaximumLikelihoodRanking::new(build_skew_symmetric_matrix(self)),
75 source_arcs: self.graph().arcs(),
76 }
77 }
78}
79
80#[cfg(feature = "example-db")]
81pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
82 use crate::export::SolutionPair;
83 use crate::solvers::BruteForce;
84
85 vec![crate::example_db::specs::RuleExampleSpec {
86 id: "minimumfeedbackarcset_to_maximumlikelihoodranking",
87 build: || {
88 let source = MinimumFeedbackArcSet::new(
89 crate::topology::DirectedGraph::new(
90 5,
91 vec![(0, 1), (1, 2), (2, 0), (2, 3), (3, 4), (4, 2), (0, 4)],
92 ),
93 vec![1i32; 7],
94 );
95 let reduction = ReduceTo::<MaximumLikelihoodRanking>::reduce_to(&source);
96 let target_witness = BruteForce::new()
97 .find_witness(reduction.target_problem())
98 .expect("target should have an optimum");
99 let source_witness = reduction.extract_solution(&target_witness);
100
101 crate::example_db::specs::rule_example_with_witness::<_, MaximumLikelihoodRanking>(
102 source,
103 SolutionPair {
104 source_config: source_witness,
105 target_config: target_witness,
106 },
107 )
108 },
109 }]
110}
111
112#[cfg(test)]
113#[path = "../unit_tests/rules/minimumfeedbackarcset_maximumlikelihoodranking.rs"]
114mod tests;