problemreductions/models/graph/
hamiltonian_path_between_two_vertices.rs1use crate::registry::{FieldInfo, ProblemSchemaEntry, VariantDimension};
8use crate::topology::{Graph, SimpleGraph};
9use crate::traits::Problem;
10use crate::variant::VariantParam;
11use serde::{Deserialize, Serialize};
12
13inventory::submit! {
14 ProblemSchemaEntry {
15 name: "HamiltonianPathBetweenTwoVertices",
16 display_name: "Hamiltonian Path Between Two Vertices",
17 aliases: &[],
18 dimensions: &[
19 VariantDimension::new("graph", "SimpleGraph", &["SimpleGraph"]),
20 ],
21 module_path: module_path!(),
22 description: "Find a Hamiltonian path between two specified vertices in a graph",
23 fields: &[
24 FieldInfo { name: "graph", type_name: "G", description: "The underlying graph G=(V,E)" },
25 FieldInfo { name: "source_vertex", type_name: "usize", description: "Source vertex s" },
26 FieldInfo { name: "target_vertex", type_name: "usize", description: "Target vertex t" },
27 ],
28 }
29}
30
31#[derive(Debug, Clone, Serialize, Deserialize)]
71#[serde(bound(deserialize = "G: serde::Deserialize<'de>"))]
72pub struct HamiltonianPathBetweenTwoVertices<G> {
73 graph: G,
74 source_vertex: usize,
75 target_vertex: usize,
76}
77
78impl<G: Graph> HamiltonianPathBetweenTwoVertices<G> {
79 pub fn new(graph: G, source_vertex: usize, target_vertex: usize) -> Self {
85 let n = graph.num_vertices();
86 assert!(
87 source_vertex < n,
88 "source_vertex {source_vertex} out of range for graph with {n} vertices"
89 );
90 assert!(
91 target_vertex < n,
92 "target_vertex {target_vertex} out of range for graph with {n} vertices"
93 );
94 assert_ne!(
95 source_vertex, target_vertex,
96 "source_vertex and target_vertex must be distinct"
97 );
98 Self {
99 graph,
100 source_vertex,
101 target_vertex,
102 }
103 }
104
105 pub fn graph(&self) -> &G {
107 &self.graph
108 }
109
110 pub fn source_vertex(&self) -> usize {
112 self.source_vertex
113 }
114
115 pub fn target_vertex(&self) -> usize {
117 self.target_vertex
118 }
119
120 pub fn num_vertices(&self) -> usize {
122 self.graph.num_vertices()
123 }
124
125 pub fn num_edges(&self) -> usize {
127 self.graph.num_edges()
128 }
129
130 pub fn is_valid_solution(&self, config: &[usize]) -> bool {
132 is_valid_hamiltonian_st_path(&self.graph, config, self.source_vertex, self.target_vertex)
133 }
134}
135
136impl<G> Problem for HamiltonianPathBetweenTwoVertices<G>
137where
138 G: Graph + VariantParam,
139{
140 const NAME: &'static str = "HamiltonianPathBetweenTwoVertices";
141 type Value = crate::types::Or;
142
143 fn variant() -> Vec<(&'static str, &'static str)> {
144 crate::variant_params![G]
145 }
146
147 fn dims(&self) -> Vec<usize> {
148 let n = self.graph.num_vertices();
149 vec![n; n]
150 }
151
152 fn evaluate(&self, config: &[usize]) -> crate::types::Or {
153 crate::types::Or(is_valid_hamiltonian_st_path(
154 &self.graph,
155 config,
156 self.source_vertex,
157 self.target_vertex,
158 ))
159 }
160}
161
162pub(crate) fn is_valid_hamiltonian_st_path<G: Graph>(
169 graph: &G,
170 config: &[usize],
171 source: usize,
172 target: usize,
173) -> bool {
174 let n = graph.num_vertices();
175 if config.len() != n {
176 return false;
177 }
178
179 let mut seen = vec![false; n];
181 for &v in config {
182 if v >= n || seen[v] {
183 return false;
184 }
185 seen[v] = true;
186 }
187
188 if config[0] != source || config[n - 1] != target {
190 return false;
191 }
192
193 for i in 0..n.saturating_sub(1) {
195 if !graph.has_edge(config[i], config[i + 1]) {
196 return false;
197 }
198 }
199
200 true
201}
202
203#[cfg(feature = "example-db")]
204pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
205 vec![crate::example_db::specs::ModelExampleSpec {
208 id: "hamiltonian_path_between_two_vertices_simplegraph",
209 instance: Box::new(HamiltonianPathBetweenTwoVertices::new(
210 SimpleGraph::new(
211 6,
212 vec![
213 (0, 1),
214 (0, 3),
215 (1, 2),
216 (1, 4),
217 (2, 5),
218 (3, 4),
219 (4, 5),
220 (2, 3),
221 ],
222 ),
223 0,
224 5,
225 )),
226 optimal_config: vec![0, 3, 2, 1, 4, 5],
227 optimal_value: serde_json::json!(true),
228 }]
229}
230
231crate::declare_variants! {
233 default HamiltonianPathBetweenTwoVertices<SimpleGraph> => "1.657^num_vertices",
234}
235
236#[cfg(test)]
237#[path = "../../unit_tests/models/graph/hamiltonian_path_between_two_vertices.rs"]
238mod tests;