problemreductions/rules/
hamiltonianpathbetweentwovertices_longestpath.rs1use crate::models::graph::{HamiltonianPathBetweenTwoVertices, LongestPath};
9use crate::reduction;
10use crate::rules::traits::{ReduceTo, ReductionResult};
11use crate::topology::{Graph, SimpleGraph};
12use crate::types::One;
13
14#[derive(Debug, Clone)]
16pub struct ReductionHPBTVToLP {
17 target: LongestPath<SimpleGraph, One>,
18}
19
20impl ReductionResult for ReductionHPBTVToLP {
21 type Source = HamiltonianPathBetweenTwoVertices<SimpleGraph>;
22 type Target = LongestPath<SimpleGraph, One>;
23
24 fn target_problem(&self) -> &Self::Target {
25 &self.target
26 }
27
28 fn extract_solution(
33 &self,
34 target_solution: &<Self::Target as crate::traits::Problem>::Solution,
35 ) -> crate::rules::ExtractionResult<<Self::Source as crate::traits::Problem>::Solution> {
36 let value =
37 crate::rules::traits::validate_target_solution(self.target_problem(), target_solution)?;
38 if !crate::rules::AggregateReductionResult::extract_value(self, value).0 {
39 return Err(crate::rules::ExtractionError::invalid(
40 "target path does not certify a Hamiltonian source-target path",
41 ));
42 }
43
44 let mut adjacency = vec![Vec::new(); self.target.num_vertices()];
45 for (&selected, (u, v)) in target_solution.iter().zip(self.target.graph().edges()) {
46 if selected {
47 adjacency[u].push(v);
48 adjacency[v].push(u);
49 }
50 }
51
52 let mut current = self.target.source_vertex();
56 let mut previous = None;
57 let mut path = Vec::with_capacity(self.target.num_vertices());
58 path.push(current);
59 while let Some(&next) = adjacency[current]
60 .iter()
61 .find(|&&neighbor| Some(neighbor) != previous)
62 {
63 previous = Some(current);
64 current = next;
65 path.push(current);
66 }
67 Ok(path)
68 }
69}
70
71impl crate::rules::AggregateReductionResult for ReductionHPBTVToLP {
72 type Source = HamiltonianPathBetweenTwoVertices<SimpleGraph>;
73 type Target = LongestPath<SimpleGraph, One>;
74
75 fn target_problem(&self) -> &Self::Target {
76 &self.target
77 }
78
79 fn extract_value(&self, value: crate::types::Max<i64>) -> crate::types::Or {
80 crate::types::Or(
82 value.0.is_some_and(|length| {
83 usize::try_from(length) == Ok(self.target.num_vertices() - 1)
84 }),
85 )
86 }
87}
88
89#[reduction(
90 aggregate = custom,
91 transform = exact {
92 num_vertices = "num_vertices",
93 num_edges = "num_edges",
94 })]
95impl ReduceTo<LongestPath<SimpleGraph, One>> for HamiltonianPathBetweenTwoVertices<SimpleGraph> {
96 type Result = ReductionHPBTVToLP;
97
98 fn reduce_to(&self) -> Result<Self::Result, crate::rules::ReductionError> {
99 let graph = self.graph().clone();
100 let num_edges = graph.num_edges();
101 let edge_lengths = vec![One; num_edges];
102
103 let target = LongestPath::new(
104 graph,
105 edge_lengths,
106 self.source_vertex(),
107 self.target_vertex(),
108 );
109
110 Ok(ReductionHPBTVToLP { target })
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: "hamiltonianpathbetweentwovertices_to_longestpath",
120 build: || {
121 let source = HamiltonianPathBetweenTwoVertices::new(
123 SimpleGraph::new(5, vec![(0, 1), (1, 2), (2, 3), (3, 4)]),
124 0,
125 4,
126 );
127 crate::example_db::specs::rule_example_with_witness::<_, LongestPath<SimpleGraph, One>>(
128 source,
129 SolutionPair {
130 source_config: serde_json::json!(vec![0, 1, 2, 3, 4]),
131 target_config: serde_json::json!(vec![true, true, true, true]),
132 },
133 )
134 },
135 }]
136}
137
138#[cfg(test)]
139#[path = "../unit_tests/rules/hamiltonianpathbetweentwovertices_longestpath.rs"]
140mod tests;