problemreductions/models/graph/
hamiltonian_path.rs1use crate::registry::{FieldInfo, ProblemSchemaEntry, VariantDimension};
7use crate::topology::{Graph, SimpleGraph};
8use crate::traits::Problem;
9use crate::variant::VariantParam;
10use serde::{Deserialize, Serialize};
11
12inventory::submit! {
13 ProblemSchemaEntry {
14 name: "HamiltonianPath",
15 display_name: "Hamiltonian Path",
16 aliases: &[],
17 dimensions: &[
18 VariantDimension::new("graph", "SimpleGraph", &["SimpleGraph"]),
19 ],
20 module_path: module_path!(),
21 description: "Find a Hamiltonian path in a graph",
22 fields: &[
23 FieldInfo { name: "graph", type_name: "G", description: "The underlying graph G=(V,E)" },
24 ],
25 }
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
65#[serde(bound(deserialize = "G: serde::Deserialize<'de>"))]
66pub struct HamiltonianPath<G> {
67 graph: G,
68}
69
70impl<G: Graph> HamiltonianPath<G> {
71 pub fn new(graph: G) -> Self {
73 Self { graph }
74 }
75
76 pub fn graph(&self) -> &G {
78 &self.graph
79 }
80
81 pub fn num_vertices(&self) -> usize {
83 self.graph.num_vertices()
84 }
85
86 pub fn num_edges(&self) -> usize {
88 self.graph.num_edges()
89 }
90
91 pub fn is_valid_solution(&self, config: &[usize]) -> bool {
93 is_valid_hamiltonian_path(&self.graph, config)
94 }
95}
96
97impl<G> Problem for HamiltonianPath<G>
98where
99 G: Graph + VariantParam,
100{
101 const NAME: &'static str = "HamiltonianPath";
102 type Value = crate::types::Or;
103
104 fn variant() -> Vec<(&'static str, &'static str)> {
105 crate::variant_params![G]
106 }
107
108 fn dims(&self) -> Vec<usize> {
109 let n = self.graph.num_vertices();
110 vec![n; n]
111 }
112
113 fn evaluate(&self, config: &[usize]) -> crate::types::Or {
114 crate::types::Or(is_valid_hamiltonian_path(&self.graph, config))
115 }
116}
117
118pub(crate) fn is_valid_hamiltonian_path<G: Graph>(graph: &G, config: &[usize]) -> bool {
123 let n = graph.num_vertices();
124 if config.len() != n {
125 return false;
126 }
127
128 let mut seen = vec![false; n];
130 for &v in config {
131 if v >= n || seen[v] {
132 return false;
133 }
134 seen[v] = true;
135 }
136
137 for i in 0..n.saturating_sub(1) {
139 if !graph.has_edge(config[i], config[i + 1]) {
140 return false;
141 }
142 }
143
144 true
145}
146
147#[cfg(feature = "example-db")]
148pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
149 vec![crate::example_db::specs::ModelExampleSpec {
150 id: "hamiltonian_path_simplegraph",
151 instance: Box::new(HamiltonianPath::new(SimpleGraph::new(
152 6,
153 vec![
154 (0, 1),
155 (0, 2),
156 (1, 3),
157 (2, 3),
158 (3, 4),
159 (3, 5),
160 (4, 2),
161 (5, 1),
162 ],
163 ))),
164 optimal_config: vec![0, 2, 4, 3, 1, 5],
165 optimal_value: serde_json::json!(true),
166 }]
167}
168
169crate::declare_variants! {
171 default HamiltonianPath<SimpleGraph> => "1.657^num_vertices",
172}
173
174#[cfg(test)]
175#[path = "../../unit_tests/models/graph/hamiltonian_path.rs"]
176mod tests;