problemreductions/rules/
hamiltoniancircuit_biconnectivityaugmentation.rs1use crate::models::graph::{BiconnectivityAugmentation, HamiltonianCircuit};
22use crate::reduction;
23use crate::rules::traits::{ReduceTo, ReductionResult};
24use crate::topology::{Graph, SimpleGraph};
25
26#[derive(Debug, Clone)]
31pub struct ReductionHamiltonianCircuitToBiconnectivityAugmentation {
32 target: BiconnectivityAugmentation<SimpleGraph, i32>,
33 num_vertices: usize,
35 potential_edges: Vec<(usize, usize)>,
37}
38
39impl ReductionResult for ReductionHamiltonianCircuitToBiconnectivityAugmentation {
40 type Source = HamiltonianCircuit<SimpleGraph>;
41 type Target = BiconnectivityAugmentation<SimpleGraph, i32>;
42
43 fn target_problem(&self) -> &Self::Target {
44 &self.target
45 }
46
47 fn extract_solution(&self, target_solution: &[usize]) -> Vec<usize> {
48 let n = self.num_vertices;
49 if n < 3 {
50 return vec![0; n];
51 }
52
53 let mut adj: Vec<Vec<usize>> = vec![vec![]; n];
55 for (i, &(u, v)) in self.potential_edges.iter().enumerate() {
56 if i < target_solution.len() && target_solution[i] == 1 {
57 adj[u].push(v);
58 adj[v].push(u);
59 }
60 }
61
62 if adj.iter().any(|neighbors| neighbors.len() != 2) {
64 return vec![0; n];
65 }
66
67 let mut circuit = Vec::with_capacity(n);
69 circuit.push(0);
70 let mut prev = 0;
71 let mut current = adj[0][0];
72 while current != 0 {
73 circuit.push(current);
74 let next = if adj[current][0] == prev {
75 adj[current][1]
76 } else {
77 adj[current][0]
78 };
79 prev = current;
80 current = next;
81
82 if circuit.len() > n {
84 return vec![0; n];
85 }
86 }
87
88 if circuit.len() == n {
89 circuit
90 } else {
91 vec![0; n]
92 }
93 }
94}
95
96#[reduction(
97 overhead = {
98 num_vertices = "num_vertices",
99 num_edges = "0",
100 num_potential_edges = "num_vertices * (num_vertices - 1) / 2",
101 }
102)]
103impl ReduceTo<BiconnectivityAugmentation<SimpleGraph, i32>> for HamiltonianCircuit<SimpleGraph> {
104 type Result = ReductionHamiltonianCircuitToBiconnectivityAugmentation;
105
106 fn reduce_to(&self) -> Self::Result {
107 let n = self.num_vertices();
108 let graph = self.graph();
109
110 let initial_graph = SimpleGraph::empty(n);
112
113 let mut potential_weights = Vec::new();
115 let mut potential_edges = Vec::new();
116 for u in 0..n {
117 for v in (u + 1)..n {
118 let weight = if graph.has_edge(u, v) { 1 } else { 2 };
119 potential_weights.push((u, v, weight));
120 potential_edges.push((u, v));
121 }
122 }
123
124 let budget = n as i32;
126
127 let target = BiconnectivityAugmentation::new(initial_graph, potential_weights, budget);
128
129 ReductionHamiltonianCircuitToBiconnectivityAugmentation {
130 target,
131 num_vertices: n,
132 potential_edges,
133 }
134 }
135}
136
137#[cfg(feature = "example-db")]
138pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
139 use crate::export::SolutionPair;
140
141 vec![crate::example_db::specs::RuleExampleSpec {
142 id: "hamiltoniancircuit_to_biconnectivityaugmentation",
143 build: || {
144 let source = HamiltonianCircuit::new(SimpleGraph::cycle(4));
146 crate::example_db::specs::rule_example_with_witness::<
152 _,
153 BiconnectivityAugmentation<SimpleGraph, i32>,
154 >(
155 source,
156 SolutionPair {
157 source_config: vec![0, 1, 2, 3],
158 target_config: vec![1, 0, 1, 1, 0, 1],
159 },
160 )
161 },
162 }]
163}
164
165#[cfg(test)]
166#[path = "../unit_tests/rules/hamiltoniancircuit_biconnectivityaugmentation.rs"]
167mod tests;