problemreductions/models/graph/
hamiltonian_circuit.rs1use crate::registry::{FieldInfo, ProblemSchemaEntry, VariantDimension};
7use crate::topology::{Graph, SimpleGraph};
8use crate::traits::{Problem, SatisfactionProblem};
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 module_path: module_path!(),
21 description: "Does the graph contain a Hamiltonian circuit?",
22 fields: &[
23 FieldInfo { name: "graph", type_name: "G", description: "The undirected graph G=(V,E)" },
24 ],
25 }
26}
27
28#[derive(Debug, Clone, Serialize, Deserialize)]
57#[serde(bound(deserialize = "G: serde::Deserialize<'de>"))]
58pub struct HamiltonianCircuit<G> {
59 graph: G,
61}
62
63impl<G: Graph> HamiltonianCircuit<G> {
64 pub fn new(graph: G) -> Self {
66 Self { graph }
67 }
68
69 pub fn graph(&self) -> &G {
71 &self.graph
72 }
73
74 pub fn num_vertices(&self) -> usize {
76 self.graph().num_vertices()
77 }
78
79 pub fn num_edges(&self) -> usize {
81 self.graph().num_edges()
82 }
83
84 pub fn is_valid_solution(&self, config: &[usize]) -> bool {
86 is_valid_hamiltonian_circuit(&self.graph, config)
87 }
88}
89
90impl<G> Problem for HamiltonianCircuit<G>
91where
92 G: Graph + VariantParam,
93{
94 const NAME: &'static str = "HamiltonianCircuit";
95 type Metric = bool;
96
97 fn variant() -> Vec<(&'static str, &'static str)> {
98 crate::variant_params![G]
99 }
100
101 fn dims(&self) -> Vec<usize> {
102 let n = self.graph.num_vertices();
103 vec![n; n]
104 }
105
106 fn evaluate(&self, config: &[usize]) -> bool {
107 is_valid_hamiltonian_circuit(&self.graph, config)
108 }
109}
110
111pub(crate) fn is_valid_hamiltonian_circuit<G: Graph>(graph: &G, config: &[usize]) -> bool {
117 let n = graph.num_vertices();
118 if n < 3 || config.len() != n {
119 return false;
120 }
121
122 let mut seen = vec![false; n];
124 for &v in config {
125 if v >= n || seen[v] {
126 return false;
127 }
128 seen[v] = true;
129 }
130
131 for i in 0..n {
133 let u = config[i];
134 let v = config[(i + 1) % n];
135 if !graph.has_edge(u, v) {
136 return false;
137 }
138 }
139
140 true
141}
142
143impl<G: Graph + VariantParam> SatisfactionProblem for HamiltonianCircuit<G> {}
144
145#[cfg(feature = "example-db")]
146pub(crate) fn canonical_model_example_specs() -> Vec<crate::example_db::specs::ModelExampleSpec> {
147 vec![crate::example_db::specs::ModelExampleSpec {
148 id: "hamiltonian_circuit_simplegraph",
149 instance: Box::new(HamiltonianCircuit::new(SimpleGraph::new(
151 6,
152 vec![
153 (0, 1),
154 (1, 2),
155 (2, 0),
156 (3, 4),
157 (4, 5),
158 (5, 3),
159 (0, 3),
160 (1, 4),
161 (2, 5),
162 ],
163 ))),
164 optimal_config: vec![0, 1, 2, 5, 4, 3],
165 optimal_value: serde_json::json!(true),
166 }]
167}
168
169crate::declare_variants! {
170 default sat HamiltonianCircuit<SimpleGraph> => "1.657^num_vertices",
171}
172
173#[cfg(test)]
174#[path = "../../unit_tests/models/graph/hamiltonian_circuit.rs"]
175mod tests;