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<i64>,
19 n: usize,
20}
21
22impl ReductionResult for ReductionHamiltonianCircuitToStrongConnectivityAugmentation {
23 type Source = HamiltonianCircuit<SimpleGraph>;
24 type Target = StrongConnectivityAugmentation<i64>;
25
26 fn target_problem(&self) -> &Self::Target {
27 &self.target
28 }
29
30 fn extract_solution(
31 &self,
32 target_solution: &<Self::Target as crate::traits::Problem>::Solution,
33 ) -> crate::rules::ExtractionResult<<Self::Source as crate::traits::Problem>::Solution> {
34 crate::rules::traits::validate_target_solution(self.target_problem(), target_solution)?;
35
36 Ok({
37 let n = self.n;
38 if n == 0 {
39 return Ok(vec![]);
40 }
41
42 let candidate_arcs = self.target.candidate_arcs();
44 let mut successors = vec![Vec::new(); n];
45 for (idx, &selected) in target_solution.iter().enumerate() {
46 if selected {
47 let (u, v, _) = candidate_arcs[idx];
48 successors[u].push(v);
49 }
50 }
51
52 let mut order = Vec::with_capacity(n);
54 let mut current = 0;
55 let mut visited = vec![false; n];
56 for _ in 0..n {
57 if visited[current] {
58 return Err(crate::rules::ExtractionError::invalid(
59 "selected arcs revisit a source vertex",
60 ));
61 }
62 visited[current] = true;
63 order.push(current);
64 if successors[current].len() != 1 {
65 return Err(crate::rules::ExtractionError::invalid(
66 "selected arcs do not provide one successor for every source vertex",
67 ));
68 }
69 current = successors[current][0];
70 }
71
72 order
73 })
74 }
75}
76
77#[reduction(
78 transform = exact {
79 num_vertices = "num_vertices",
80 num_arcs = "0",
81 num_potential_arcs = "num_vertices * (num_vertices - 1)",
82 }
83)]
84impl ReduceTo<StrongConnectivityAugmentation<i64>> for HamiltonianCircuit<SimpleGraph> {
85 type Result = ReductionHamiltonianCircuitToStrongConnectivityAugmentation;
86
87 fn reduce_to(&self) -> Result<Self::Result, crate::rules::ReductionError> {
88 let n = self.num_vertices();
89 let graph = DirectedGraph::empty(n);
90
91 let mut candidate_arcs = Vec::with_capacity(n * (n - 1));
93 for u in 0..n {
94 for v in 0..n {
95 if u != v {
96 let weight = if self.graph().has_edge(u, v) { 1 } else { 2 };
97 candidate_arcs.push((u, v, weight));
98 }
99 }
100 }
101
102 let bound = i64::try_from(n).map_err(|_| {
103 crate::rules::ReductionError::integer_overflow::<
104 HamiltonianCircuit<SimpleGraph>,
105 StrongConnectivityAugmentation<i64>,
106 >("converting the vertex count to the target bound")
107 })?;
108 let target = StrongConnectivityAugmentation::new(graph, candidate_arcs, bound);
109
110 Ok(ReductionHamiltonianCircuitToStrongConnectivityAugmentation { target, n })
111 }
112}
113
114#[cfg(feature = "example-db")]
115pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
116 use crate::export::SolutionPair;
117
118 vec![crate::example_db::specs::RuleExampleSpec {
119 id: "hamiltoniancircuit_to_strongconnectivityaugmentation",
120 build: || {
121 let source = HamiltonianCircuit::new(SimpleGraph::cycle(4));
123 let reduction = ReduceTo::<StrongConnectivityAugmentation<i64>>::reduce_to(&source)
124 .expect("reduction should succeed");
125 let target = reduction.target_problem();
126
127 let n = 4;
133 let mut target_config = vec![false; n * (n - 1)];
134 let cycle_arcs = [(0, 1), (1, 2), (2, 3), (3, 0)];
135 for (u, v) in cycle_arcs {
136 let idx = u * (n - 1) + if v > u { v - 1 } else { v };
137 target_config[idx] = true;
138 }
139
140 assert!(
142 target.is_valid_solution(&target_config).unwrap(),
143 "canonical target config must be a valid SCA solution"
144 );
145
146 crate::example_db::specs::assemble_rule_example(
147 &source,
148 target,
149 vec![SolutionPair {
150 source_config: serde_json::json!(vec![0, 1, 2, 3]),
151 target_config: serde_json::to_value(target_config)
152 .expect("solution serialization must succeed"),
153 }],
154 )
155 },
156 }]
157}
158
159#[cfg(test)]
160#[path = "../unit_tests/rules/hamiltoniancircuit_strongconnectivityaugmentation.rs"]
161mod tests;