problemreductions/models/graph/
hamiltonian_circuit.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: "HamiltonianCircuit",
15 display_name: "Hamiltonian Circuit",
16 aliases: &["HC"],
17 dimensions: &[
18 VariantDimension::new("graph", "SimpleGraph", &["SimpleGraph"]),
19 ],
20 category: crate::registry::ProblemCategory::Graph,
21 module_path: module_path!(),
22 description: "Does the graph contain a Hamiltonian circuit?",
23 fields: &[
24 FieldInfo { name: "graph", type_name: "G", description: "The undirected graph G=(V,E)" },
25 ],
26 }
27}
28
29#[derive(Debug, Clone, Serialize, Deserialize)]
58#[serde(bound(deserialize = "G: serde::Deserialize<'de>"))]
59pub struct HamiltonianCircuit<G> {
60 graph: G,
62}
63
64impl<G: Graph> HamiltonianCircuit<G> {
65 pub fn new(graph: G) -> Self {
67 Self { graph }
68 }
69
70 pub fn graph(&self) -> &G {
72 &self.graph
73 }
74
75 pub fn num_vertices(&self) -> usize {
77 self.graph().num_vertices()
78 }
79
80 pub fn num_edges(&self) -> usize {
82 self.graph().num_edges()
83 }
84
85 pub fn is_valid_solution(&self, config: &[usize]) -> bool {
87 is_valid_hamiltonian_circuit(&self.graph, config)
88 }
89}
90
91impl<G> Problem for HamiltonianCircuit<G>
92where
93 G: Graph + VariantParam,
94{
95 const NAME: &'static str = "HamiltonianCircuit";
96 type Solution = Vec<usize>;
97 type Value = crate::types::Or;
98
99 crate::problem_parameters![("num_edges", num_edges), ("num_vertices", num_vertices),];
100
101 fn variant() -> Vec<(&'static str, &'static str)> {
102 crate::variant_params![G]
103 }
104
105 fn evaluate(
106 &self,
107 config: &Self::Solution,
108 ) -> Result<crate::types::Or, crate::traits::EvaluationError> {
109 let n = self.graph.num_vertices();
110 if config.len() != n {
111 return Err(crate::traits::EvaluationError::InvalidConfiguration(
112 "circuit ordering length does not match the graph vertices".into(),
113 ));
114 }
115 if config.iter().any(|&vertex| vertex >= n) {
116 return Err(crate::traits::EvaluationError::InvalidConfiguration(
117 "circuit ordering contains an out-of-range vertex".into(),
118 ));
119 }
120 Ok(crate::types::Or(is_valid_hamiltonian_circuit(
121 &self.graph,
122 config,
123 )))
124 }
125}
126
127impl<G> crate::solvers::BruteForceProblem for HamiltonianCircuit<G>
128where
129 G: Graph + VariantParam,
130{
131 fn dimensions(&self) -> Vec<usize> {
132 let n = self.graph.num_vertices();
133 vec![n; n]
134 }
135}
136
137pub(crate) fn is_valid_hamiltonian_circuit<G: Graph>(graph: &G, config: &[usize]) -> bool {
143 let n = graph.num_vertices();
144 if n < 3 || config.len() != n {
145 return false;
146 }
147
148 let mut seen = vec![false; n];
150 for &v in config {
151 if v >= n || seen[v] {
152 return false;
153 }
154 seen[v] = true;
155 }
156
157 for i in 0..n {
159 let u = config[i];
160 let v = config[(i + 1) % n];
161 if !graph.has_edge(u, v) {
162 return false;
163 }
164 }
165
166 true
167}
168
169#[cfg(feature = "example-db")]
170pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
171 vec![crate::example_db::specs::ModelExampleSpec {
172 id: "hamiltonian_circuit_simplegraph",
173 instance: Box::new(HamiltonianCircuit::new(SimpleGraph::new(
175 6,
176 vec![
177 (0, 1),
178 (1, 2),
179 (2, 0),
180 (3, 4),
181 (4, 5),
182 (5, 3),
183 (0, 3),
184 (1, 4),
185 (2, 5),
186 ],
187 ))),
188 optimal_config: serde_json::json!(vec![0, 1, 2, 5, 4, 3]),
189 optimal_value: serde_json::json!(true),
190 }]
191}
192
193crate::impl_random_generate!(
194 HamiltonianCircuit<SimpleGraph>,
195 crate::random::SimpleGraphRandomSpec,
196 |spec| { Ok(HamiltonianCircuit::new(spec.graph()?)) }
197);
198
199crate::declare_variants! {
200 default HamiltonianCircuit<SimpleGraph> => "1.657^num_vertices" random,
201}
202
203crate::register_brute_force! {
204 HamiltonianCircuit<SimpleGraph>,
205}
206
207#[cfg(test)]
208#[path = "../../unit_tests/models/graph/hamiltonian_circuit.rs"]
209mod tests;