Skip to main content

problemreductions/rules/
hamiltonianpath_isomorphicspanningtree.rs

1//! Reduction from HamiltonianPath to `IsomorphicSpanningTree<SimpleGraph>`.
2//!
3//! A Hamiltonian path in G exists iff G has a spanning tree isomorphic to the
4//! path graph P_n. The reduction keeps G unchanged as the host graph and
5//! constructs T = P_n (the path on n vertices: edges {0,1},{1,2},...,{n-2,n-1}).
6
7use crate::models::graph::{HamiltonianPath, IsomorphicSpanningTree};
8use crate::reduction;
9use crate::rules::traits::{ReduceTo, ReductionResult};
10use crate::topology::SimpleGraph;
11
12/// Result of reducing HamiltonianPath to IsomorphicSpanningTree<SimpleGraph>.
13#[derive(Debug, Clone)]
14pub struct ReductionHPToIST {
15    target: IsomorphicSpanningTree<SimpleGraph>,
16}
17
18impl ReductionResult for ReductionHPToIST {
19    type Source = HamiltonianPath<SimpleGraph>;
20    type Target = IsomorphicSpanningTree<SimpleGraph>;
21
22    fn target_problem(&self) -> &Self::Target {
23        &self.target
24    }
25
26    /// Solution extraction: identity mapping.
27    ///
28    /// The IST config maps tree vertex i to graph vertex config[i]. Since the
29    /// tree is P_n (path 0-1-2-...-n-1), this mapping directly gives the
30    /// vertex ordering of the Hamiltonian path.
31    fn extract_solution(
32        &self,
33        target_solution: &<Self::Target as crate::traits::Problem>::Solution,
34    ) -> crate::rules::ExtractionResult<<Self::Source as crate::traits::Problem>::Solution> {
35        crate::rules::traits::validate_target_solution(self.target_problem(), target_solution)?;
36
37        Ok(target_solution.to_vec())
38    }
39}
40
41#[reduction(
42    transform = exact {
43        num_vertices = "num_vertices",
44        num_edges = "num_edges",
45    }
46)]
47impl ReduceTo<IsomorphicSpanningTree<SimpleGraph>> for HamiltonianPath<SimpleGraph> {
48    type Result = ReductionHPToIST;
49
50    fn reduce_to(&self) -> Result<Self::Result, crate::rules::ReductionError> {
51        let n = self.num_vertices();
52
53        // Host graph: keep G unchanged
54        let graph = self.graph().clone();
55
56        let tree = SimpleGraph::path(n);
57
58        Ok(ReductionHPToIST {
59            target: IsomorphicSpanningTree::new(graph, tree),
60        })
61    }
62}
63
64#[cfg(feature = "example-db")]
65pub(crate) fn canonical_rule_example_specs() -> Vec<crate::example_db::specs::RuleExampleSpec> {
66    use crate::export::SolutionPair;
67
68    vec![crate::example_db::specs::RuleExampleSpec {
69        id: "hamiltonianpath_to_isomorphicspanningtree",
70        build: || {
71            // Path graph 0-1-2-3-4 has a trivial Hamiltonian path
72            let source = HamiltonianPath::new(SimpleGraph::path(5));
73            crate::example_db::specs::rule_example_with_witness::<
74                _,
75                IsomorphicSpanningTree<SimpleGraph>,
76            >(
77                source,
78                SolutionPair {
79                    source_config: serde_json::json!(vec![0, 1, 2, 3, 4]),
80                    target_config: serde_json::json!(vec![0, 1, 2, 3, 4]),
81                },
82            )
83        },
84    }]
85}
86
87#[cfg(test)]
88#[path = "../unit_tests/rules/hamiltonianpath_isomorphicspanningtree.rs"]
89mod tests;