problemreductions/rules/
hamiltoniancircuit_strongconnectivityaugmentation.rs1use crate::models::graph::{HamiltonianCircuit, StrongConnectivityAugmentation};
11use crate::reduction;
12use crate::rules::traits::{ReduceTo, ReductionResult};
13use crate::topology::{DirectedGraph, Graph, SimpleGraph};
14
15#[derive(Debug, Clone)]
17pub struct ReductionHamiltonianCircuitToStrongConnectivityAugmentation {
18 target: StrongConnectivityAugmentation<i32>,
19 n: usize,
20}
21
22impl ReductionResult for ReductionHamiltonianCircuitToStrongConnectivityAugmentation {
23 type Source = HamiltonianCircuit<SimpleGraph>;
24 type Target = StrongConnectivityAugmentation<i32>;
25
26 fn target_problem(&self) -> &Self::Target {
27 &self.target
28 }
29
30 fn extract_solution(&self, target_solution: &[usize]) -> Vec<usize> {
31 let n = self.n;
32 if n == 0 {
33 return vec![];
34 }
35
36 let candidate_arcs = self.target.candidate_arcs();
38 let mut successors = vec![Vec::new(); n];
39 for (idx, &selected) in target_solution.iter().enumerate() {
40 if selected == 1 {
41 let (u, v, _) = candidate_arcs[idx];
42 successors[u].push(v);
43 }
44 }
45
46 let mut order = Vec::with_capacity(n);
48 let mut current = 0;
49 let mut visited = vec![false; n];
50 for _ in 0..n {
51 if visited[current] {
52 return vec![0; n];
54 }
55 visited[current] = true;
56 order.push(current);
57 if successors[current].len() != 1 {
58 return vec![0; n];
59 }
60 current = successors[current][0];
61 }
62
63 order
64 }
65}
66
67#[reduction(
68 overhead = {
69 num_vertices = "num_vertices",
70 num_arcs = "0",
71 num_potential_arcs = "num_vertices * (num_vertices - 1)",
72 }
73)]
74impl ReduceTo<StrongConnectivityAugmentation<i32>> for HamiltonianCircuit<SimpleGraph> {
75 type Result = ReductionHamiltonianCircuitToStrongConnectivityAugmentation;
76
77 fn reduce_to(&self) -> Self::Result {
78 let n = self.num_vertices();
79 let graph = DirectedGraph::empty(n);
80
81 let mut candidate_arcs = Vec::with_capacity(n * (n - 1));
83 for u in 0..n {
84 for v in 0..n {
85 if u != v {
86 let weight = if self.graph().has_edge(u, v) { 1 } else { 2 };
87 candidate_arcs.push((u, v, weight));
88 }
89 }
90 }
91
92 let bound = n as i32;
93 let target = StrongConnectivityAugmentation::new(graph, candidate_arcs, bound);
94
95 ReductionHamiltonianCircuitToStrongConnectivityAugmentation { target, n }
96 }
97}
98
99#[cfg(feature = "example-db")]
100pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
101 use crate::export::SolutionPair;
102
103 vec![crate::example_db::specs::RuleExampleSpec {
104 id: "hamiltoniancircuit_to_strongconnectivityaugmentation",
105 build: || {
106 let source = HamiltonianCircuit::new(SimpleGraph::cycle(4));
108 let reduction = ReduceTo::<StrongConnectivityAugmentation<i32>>::reduce_to(&source);
109 let target = reduction.target_problem();
110
111 let n = 4;
117 let mut target_config = vec![0usize; n * (n - 1)];
118 let cycle_arcs = [(0, 1), (1, 2), (2, 3), (3, 0)];
119 for (u, v) in cycle_arcs {
120 let idx = u * (n - 1) + if v > u { v - 1 } else { v };
121 target_config[idx] = 1;
122 }
123
124 assert!(
126 target.is_valid_solution(&target_config),
127 "canonical target config must be a valid SCA solution"
128 );
129
130 crate::example_db::specs::assemble_rule_example(
131 &source,
132 target,
133 vec![SolutionPair {
134 source_config: vec![0, 1, 2, 3],
135 target_config,
136 }],
137 )
138 },
139 }]
140}
141
142#[cfg(test)]
143#[path = "../unit_tests/rules/hamiltoniancircuit_strongconnectivityaugmentation.rs"]
144mod tests;