problemreductions/rules/
hamiltoniancircuit_hamiltonianpath.rs1use crate::models::graph::{HamiltonianCircuit, HamiltonianPath};
16use crate::reduction;
17use crate::rules::traits::{ReduceTo, ReductionResult};
18use crate::topology::{Graph, SimpleGraph};
19
20#[derive(Debug, Clone)]
25pub struct ReductionHamiltonianCircuitToHamiltonianPath {
26 target: HamiltonianPath<SimpleGraph>,
27 num_original_vertices: usize,
29}
30
31impl ReductionResult for ReductionHamiltonianCircuitToHamiltonianPath {
32 type Source = HamiltonianCircuit<SimpleGraph>;
33 type Target = HamiltonianPath<SimpleGraph>;
34
35 fn target_problem(&self) -> &Self::Target {
36 &self.target
37 }
38
39 fn extract_solution(
40 &self,
41 target_solution: &<Self::Target as crate::traits::Problem>::Solution,
42 ) -> crate::rules::ExtractionResult<<Self::Source as crate::traits::Problem>::Solution> {
43 crate::rules::traits::validate_target_solution(self.target_problem(), target_solution)?;
44
45 Ok({
46 let n = self.num_original_vertices;
47 if n == 0 {
48 return Ok(vec![]);
49 }
50
51 let v_prime = n; let s = n + 1; let t = n + 2; let reversed;
57 let oriented = match (target_solution.first(), target_solution.last()) {
58 (Some(&start), Some(&end)) if start == s && end == t => target_solution,
59 (Some(&start), Some(&end)) if start == t && end == s => {
60 reversed = target_solution.iter().copied().rev().collect::<Vec<_>>();
61 reversed.as_slice()
62 }
63 _ => {
64 return Err(crate::rules::ExtractionError::invalid(
65 "target path does not have the required pendant endpoints",
66 ))
67 }
68 };
69
70 if oriented.get(1) != Some(&0) || oriented.get(n + 1) != Some(&v_prime) {
71 return Err(crate::rules::ExtractionError::invalid(
72 "target path does not traverse the duplicated source vertex correctly",
73 ));
74 }
75
76 oriented[1..=n].to_vec()
77 })
78 }
79}
80
81#[reduction(
82 transform = upper_bound {
83 num_vertices = "num_vertices + 3",
84 num_edges = "num_edges + num_vertices + 1",
85 }
86)]
87impl ReduceTo<HamiltonianPath<SimpleGraph>> for HamiltonianCircuit<SimpleGraph> {
88 type Result = ReductionHamiltonianCircuitToHamiltonianPath;
89
90 fn reduce_to(&self) -> Result<Self::Result, crate::rules::ReductionError> {
91 let n = self.num_vertices();
92
93 if n < 3 {
95 let target_graph = SimpleGraph::empty(n + 3);
96 let target = HamiltonianPath::new(target_graph);
97 return Ok(ReductionHamiltonianCircuitToHamiltonianPath {
98 target,
99 num_original_vertices: n,
100 });
101 }
102
103 let source_graph = self.graph();
104
105 let v_prime = n;
111 let s = n + 1;
112 let t = n + 2;
113
114 let mut edges: Vec<(usize, usize)> = Vec::new();
115
116 for (u, v) in source_graph.edges() {
118 edges.push((u, v));
119 }
120
121 for neighbor in source_graph.neighbors(0) {
123 edges.push((v_prime, neighbor));
124 }
125
126 edges.push((s, 0));
128
129 edges.push((t, v_prime));
131
132 let target_graph = SimpleGraph::new(n + 3, edges);
133 let target = HamiltonianPath::new(target_graph);
134
135 Ok(ReductionHamiltonianCircuitToHamiltonianPath {
136 target,
137 num_original_vertices: n,
138 })
139 }
140}
141
142#[cfg(feature = "example-db")]
143pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
144 use crate::export::SolutionPair;
145
146 vec![crate::example_db::specs::RuleExampleSpec {
147 id: "hamiltoniancircuit_to_hamiltonianpath",
148 build: || {
149 let source = HamiltonianCircuit::new(SimpleGraph::cycle(4));
151 crate::example_db::specs::rule_example_with_witness::<_, HamiltonianPath<SimpleGraph>>(
152 source,
153 SolutionPair {
154 source_config: serde_json::json!(vec![0, 1, 2, 3]),
156 target_config: serde_json::json!(vec![5, 0, 1, 2, 3, 4, 6]),
158 },
159 )
160 },
161 }]
162}
163
164#[cfg(test)]
165#[path = "../unit_tests/rules/hamiltoniancircuit_hamiltonianpath.rs"]
166mod tests;