diff --git a/docs/paper/reductions.typ b/docs/paper/reductions.typ index c34812b5b..8298a429c 100644 --- a/docs/paper/reductions.typ +++ b/docs/paper/reductions.typ @@ -30,6 +30,7 @@ "MinimumVertexCover": [Minimum Vertex Cover], "MaxCut": [Max-Cut], "GraphPartitioning": [Graph Partitioning], + "HamiltonianPath": [Hamiltonian Path], "KColoring": [$k$-Coloring], "MinimumDominatingSet": [Minimum Dominating Set], "MaximumMatching": [Maximum Matching], @@ -439,6 +440,15 @@ Graph Partitioning is a core NP-hard problem arising in VLSI design, parallel co caption: [Graph with $n = 6$ vertices partitioned into $A = {v_0, v_1, v_2}$ (blue) and $B = {v_3, v_4, v_5}$ (red). The 3 crossing edges $(v_1, v_3)$, $(v_2, v_3)$, $(v_2, v_4)$ are shown in bold red; internal edges are gray.], ) ] +#problem-def("HamiltonianPath")[ + Given a graph $G = (V, E)$, determine whether $G$ contains a _Hamiltonian path_, i.e., a simple path that visits every vertex exactly once. +][ + A classical NP-complete decision problem from Garey & Johnson (A1.3 GT39), closely related to _Hamiltonian Circuit_. Finding a Hamiltonian path in $G$ is equivalent to finding a Hamiltonian circuit in an augmented graph $G'$ obtained by adding a new vertex adjacent to all vertices of $G$. The problem remains NP-complete for planar graphs, cubic graphs, and bipartite graphs. + + The best known exact algorithm is Björklund's randomized $O^*(1.657^n)$ "Determinant Sums" method @bjorklund2014, which applies to both Hamiltonian path and circuit. The classical Held--Karp dynamic programming algorithm solves it in $O(n^2 dot 2^n)$ deterministic time. + + Variables: $n = |V|$ values forming a permutation. Position $i$ holds the vertex visited at step $i$. A configuration is satisfying when it forms a valid permutation of all vertices and consecutive vertices are adjacent in $G$. +] #problem-def("KColoring")[ Given $G = (V, E)$ and $k$ colors, find $c: V -> {1, ..., k}$ minimizing $|{(u, v) in E : c(u) = c(v)}|$. ][ diff --git a/docs/paper/references.bib b/docs/paper/references.bib index 94dcd02f1..d73afb4e3 100644 --- a/docs/paper/references.bib +++ b/docs/paper/references.bib @@ -196,6 +196,17 @@ @article{bjorklund2009 doi = {10.1137/070683933} } +@article{bjorklund2014, + author = {Andreas Bj{\"o}rklund}, + title = {Determinant Sums for Undirected Hamiltonicity}, + journal = {SIAM Journal on Computing}, + volume = {43}, + number = {1}, + pages = {280--299}, + year = {2014}, + doi = {10.1137/110839229}, +} + @article{aspvall1979, author = {Bengt Aspvall and Michael F. Plass and Robert Endre Tarjan}, title = {A Linear-Time Algorithm for Testing the Truth of Certain Quantified Boolean Formulas}, diff --git a/docs/src/reductions/problem_schemas.json b/docs/src/reductions/problem_schemas.json index 6358e5906..03bee10c8 100644 --- a/docs/src/reductions/problem_schemas.json +++ b/docs/src/reductions/problem_schemas.json @@ -121,6 +121,17 @@ } ] }, + { + "name": "HamiltonianPath", + "description": "Find a Hamiltonian path in a graph", + "fields": [ + { + "name": "graph", + "type_name": "G", + "description": "The underlying graph G=(V,E)" + } + ] + }, { "name": "ILP", "description": "Optimize linear objective subject to linear constraints", diff --git a/examples/hamiltonian_path.rs b/examples/hamiltonian_path.rs new file mode 100644 index 000000000..311a03c38 --- /dev/null +++ b/examples/hamiltonian_path.rs @@ -0,0 +1,41 @@ +use problemreductions::models::graph::HamiltonianPath; +use problemreductions::topology::SimpleGraph; +use problemreductions::{BruteForce, Problem}; + +pub fn run() { + // Instance 2 from issue: 6 vertices, 8 edges (non-trivial) + let graph = SimpleGraph::new( + 6, + vec![ + (0, 1), + (0, 2), + (1, 3), + (2, 3), + (3, 4), + (3, 5), + (4, 2), + (5, 1), + ], + ); + let problem = HamiltonianPath::new(graph); + + println!("HamiltonianPath instance:"); + println!(" Vertices: {}", problem.num_vertices()); + println!(" Edges: {}", problem.num_edges()); + + let json = serde_json::to_string_pretty(&problem).unwrap(); + println!(" JSON: {}", json); + + // Find all Hamiltonian paths + let solver = BruteForce::new(); + let solutions = solver.find_all_satisfying(&problem); + println!(" Solutions found: {}", solutions.len()); + + for (i, sol) in solutions.iter().enumerate() { + println!(" Path {}: {:?} (valid: {})", i, sol, problem.evaluate(sol)); + } +} + +fn main() { + run(); +} diff --git a/problemreductions-cli/src/commands/create.rs b/problemreductions-cli/src/commands/create.rs index 9c66facc9..beb1113d0 100644 --- a/problemreductions-cli/src/commands/create.rs +++ b/problemreductions-cli/src/commands/create.rs @@ -5,7 +5,7 @@ use crate::problem_name::{parse_problem_spec, resolve_variant}; use crate::util; use anyhow::{bail, Context, Result}; use problemreductions::models::algebraic::{ClosestVectorProblem, BMF}; -use problemreductions::models::graph::GraphPartitioning; +use problemreductions::models::graph::{GraphPartitioning, HamiltonianPath}; use problemreductions::models::misc::{BinPacking, LongestCommonSubsequence, PaintShop, SubsetSum}; use problemreductions::prelude::*; use problemreductions::registry::collect_schemas; @@ -85,6 +85,7 @@ fn example_for(canonical: &str, graph_type: Option<&str>) -> &'static str { _ => "--graph 0-1,1-2,2-3 --weights 1,1,1,1", }, "GraphPartitioning" => "--graph 0-1,1-2,2-3,0-2,1-3,0-3", + "HamiltonianPath" => "--graph 0-1,1-2,2-3", "MaxCut" | "MaximumMatching" | "TravelingSalesman" => { "--graph 0-1,1-2,2-3 --edge-weights 1,1,1" } @@ -228,6 +229,19 @@ pub fn create(args: &CreateArgs, out: &OutputConfig) -> Result<()> { ) } + // Hamiltonian path (graph only, no weights) + "HamiltonianPath" => { + let (graph, _) = parse_graph(args).map_err(|e| { + anyhow::anyhow!( + "{e}\n\nUsage: pred create HamiltonianPath --graph 0-1,1-2,2-3" + ) + })?; + ( + ser(HamiltonianPath::new(graph))?, + resolved_variant.clone(), + ) + } + // Graph problems with edge weights "MaxCut" | "MaximumMatching" | "TravelingSalesman" => { let (graph, _) = parse_graph(args).map_err(|e| { @@ -1204,6 +1218,17 @@ fn create_random( (ser(GraphPartitioning::new(graph))?, variant) } + // HamiltonianPath (graph only, no weights) + "HamiltonianPath" => { + let edge_prob = args.edge_prob.unwrap_or(0.5); + if !(0.0..=1.0).contains(&edge_prob) { + bail!("--edge-prob must be between 0.0 and 1.0"); + } + let graph = util::create_random_graph(num_vertices, edge_prob, args.seed); + let variant = variant_map(&[("graph", "SimpleGraph")]); + (ser(HamiltonianPath::new(graph))?, variant) + } + // Graph problems with edge weights "MaxCut" | "MaximumMatching" | "TravelingSalesman" => { let edge_prob = args.edge_prob.unwrap_or(0.5); @@ -1255,7 +1280,8 @@ fn create_random( _ => bail!( "Random generation is not supported for {canonical}. \ Supported: graph-based problems (MIS, MVC, MaxCut, MaxClique, \ - MaximumMatching, MinimumDominatingSet, SpinGlass, KColoring, TravelingSalesman)" + MaximumMatching, MinimumDominatingSet, SpinGlass, KColoring, TravelingSalesman, \ + HamiltonianPath)" ), }; diff --git a/problemreductions-cli/src/dispatch.rs b/problemreductions-cli/src/dispatch.rs index 5d7f71cda..480f05fc7 100644 --- a/problemreductions-cli/src/dispatch.rs +++ b/problemreductions-cli/src/dispatch.rs @@ -212,6 +212,7 @@ pub fn load_problem( "MinimumDominatingSet" => deser_opt::>(data), "MinimumSumMulticenter" => deser_opt::>(data), "GraphPartitioning" => deser_opt::>(data), + "HamiltonianPath" => deser_sat::>(data), "MaxCut" => deser_opt::>(data), "MaximalIS" => deser_opt::>(data), "TravelingSalesman" => deser_opt::>(data), @@ -278,6 +279,7 @@ pub fn serialize_any_problem( "MinimumDominatingSet" => try_ser::>(any), "MinimumSumMulticenter" => try_ser::>(any), "GraphPartitioning" => try_ser::>(any), + "HamiltonianPath" => try_ser::>(any), "MaxCut" => try_ser::>(any), "MaximalIS" => try_ser::>(any), "TravelingSalesman" => try_ser::>(any), diff --git a/problemreductions-cli/src/problem_name.rs b/problemreductions-cli/src/problem_name.rs index 582430c52..b01fe0060 100644 --- a/problemreductions-cli/src/problem_name.rs +++ b/problemreductions-cli/src/problem_name.rs @@ -66,6 +66,7 @@ pub fn resolve_alias(input: &str) -> String { "fas" | "minimumfeedbackarcset" => "MinimumFeedbackArcSet".to_string(), "minimumsummulticenter" | "pmedian" => "MinimumSumMulticenter".to_string(), "subsetsum" => "SubsetSum".to_string(), + "hamiltonianpath" => "HamiltonianPath".to_string(), _ => input.to_string(), // pass-through for exact names } } diff --git a/src/lib.rs b/src/lib.rs index 95caa1aaf..6d9cd9a1d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -41,7 +41,7 @@ pub mod prelude { pub use crate::models::algebraic::{BMF, QUBO}; pub use crate::models::formula::{CNFClause, CircuitSAT, KSatisfiability, Satisfiability}; pub use crate::models::graph::{ - BicliqueCover, GraphPartitioning, SpinGlass, SubgraphIsomorphism, + BicliqueCover, GraphPartitioning, HamiltonianPath, SpinGlass, SubgraphIsomorphism, }; pub use crate::models::graph::{ KColoring, MaxCut, MaximalIS, MaximumClique, MaximumIndependentSet, MaximumMatching, diff --git a/src/models/graph/hamiltonian_path.rs b/src/models/graph/hamiltonian_path.rs new file mode 100644 index 000000000..7fabfc1c9 --- /dev/null +++ b/src/models/graph/hamiltonian_path.rs @@ -0,0 +1,151 @@ +//! Hamiltonian Path problem implementation. +//! +//! The Hamiltonian Path problem asks whether a graph contains a simple path +//! that visits every vertex exactly once. + +use crate::registry::{FieldInfo, ProblemSchemaEntry}; +use crate::topology::{Graph, SimpleGraph}; +use crate::traits::{Problem, SatisfactionProblem}; +use crate::variant::VariantParam; +use serde::{Deserialize, Serialize}; + +inventory::submit! { + ProblemSchemaEntry { + name: "HamiltonianPath", + module_path: module_path!(), + description: "Find a Hamiltonian path in a graph", + fields: &[ + FieldInfo { name: "graph", type_name: "G", description: "The underlying graph G=(V,E)" }, + ], + } +} + +/// The Hamiltonian Path problem. +/// +/// Given a graph G = (V, E), determine whether G contains a Hamiltonian path, +/// i.e., a simple path that visits every vertex exactly once. +/// +/// # Representation +/// +/// A configuration is a sequence of `n` vertex indices representing a vertex +/// ordering (permutation). Each position `i` in the configuration holds the +/// vertex visited at step `i`. A valid solution must be a permutation of +/// `0..n` where consecutive entries are adjacent in the graph. +/// +/// The search space has `dims() = [n; n]` (each position can hold any of `n` +/// vertices), so brute-force enumerates `n^n` configurations. Only `n!` +/// permutations can satisfy the constraints, but the encoding avoids complex +/// variable-domain schemes and matches the problem's natural formulation. +/// +/// # Type Parameters +/// +/// * `G` - Graph type (e.g., SimpleGraph) +/// +/// # Example +/// +/// ``` +/// use problemreductions::models::graph::HamiltonianPath; +/// use problemreductions::topology::SimpleGraph; +/// use problemreductions::{Problem, Solver, BruteForce}; +/// +/// // Path graph: 0-1-2-3 +/// let graph = SimpleGraph::new(4, vec![(0, 1), (1, 2), (2, 3)]); +/// let problem = HamiltonianPath::new(graph); +/// +/// let solver = BruteForce::new(); +/// let solution = solver.find_satisfying(&problem); +/// assert!(solution.is_some()); +/// ``` +#[derive(Debug, Clone, Serialize, Deserialize)] +#[serde(bound(deserialize = "G: serde::Deserialize<'de>"))] +pub struct HamiltonianPath { + graph: G, +} + +impl HamiltonianPath { + /// Create a new Hamiltonian Path problem from a graph. + pub fn new(graph: G) -> Self { + Self { graph } + } + + /// Get a reference to the underlying graph. + pub fn graph(&self) -> &G { + &self.graph + } + + /// Get the number of vertices in the underlying graph. + pub fn num_vertices(&self) -> usize { + self.graph.num_vertices() + } + + /// Get the number of edges in the underlying graph. + pub fn num_edges(&self) -> usize { + self.graph.num_edges() + } + + /// Check if a configuration is a valid Hamiltonian path. + pub fn is_valid_solution(&self, config: &[usize]) -> bool { + is_valid_hamiltonian_path(&self.graph, config) + } +} + +impl Problem for HamiltonianPath +where + G: Graph + VariantParam, +{ + const NAME: &'static str = "HamiltonianPath"; + type Metric = bool; + + fn variant() -> Vec<(&'static str, &'static str)> { + crate::variant_params![G] + } + + fn dims(&self) -> Vec { + let n = self.graph.num_vertices(); + vec![n; n] + } + + fn evaluate(&self, config: &[usize]) -> bool { + is_valid_hamiltonian_path(&self.graph, config) + } +} + +impl SatisfactionProblem for HamiltonianPath {} + +/// Check if a configuration represents a valid Hamiltonian path in the graph. +/// +/// A valid Hamiltonian path is a permutation of the vertices such that +/// consecutive vertices in the permutation are adjacent in the graph. +pub(crate) fn is_valid_hamiltonian_path(graph: &G, config: &[usize]) -> bool { + let n = graph.num_vertices(); + if config.len() != n { + return false; + } + + // Check that config is a valid permutation of 0..n + let mut seen = vec![false; n]; + for &v in config { + if v >= n || seen[v] { + return false; + } + seen[v] = true; + } + + // Check consecutive vertices are adjacent + for i in 0..n.saturating_sub(1) { + if !graph.has_edge(config[i], config[i + 1]) { + return false; + } + } + + true +} + +// Use Bjorklund (2014) O*(1.657^n) as best known for general undirected graphs +crate::declare_variants! { + HamiltonianPath => "1.657^num_vertices", +} + +#[cfg(test)] +#[path = "../../unit_tests/models/graph/hamiltonian_path.rs"] +mod tests; diff --git a/src/models/graph/mod.rs b/src/models/graph/mod.rs index fd8032429..b78522992 100644 --- a/src/models/graph/mod.rs +++ b/src/models/graph/mod.rs @@ -14,6 +14,7 @@ //! - [`MaximumMatching`]: Maximum weight matching //! - [`TravelingSalesman`]: Traveling Salesman (minimum weight Hamiltonian cycle) //! - [`SpinGlass`]: Ising model Hamiltonian +//! - [`HamiltonianPath`]: Hamiltonian path (simple path visiting every vertex) //! - [`BicliqueCover`]: Biclique cover on bipartite graphs //! - [`MinimumFeedbackArcSet`]: Minimum feedback arc set on directed graphs //! - [`MinimumSumMulticenter`]: Min-sum multicenter (p-median) @@ -22,6 +23,7 @@ pub(crate) mod biclique_cover; pub(crate) mod graph_partitioning; +pub(crate) mod hamiltonian_path; pub(crate) mod kcoloring; pub(crate) mod max_cut; pub(crate) mod maximal_is; @@ -41,6 +43,7 @@ pub(crate) mod traveling_salesman; pub use biclique_cover::BicliqueCover; pub use graph_partitioning::GraphPartitioning; +pub use hamiltonian_path::HamiltonianPath; pub use kcoloring::KColoring; pub use max_cut::MaxCut; pub use maximal_is::MaximalIS; diff --git a/src/models/mod.rs b/src/models/mod.rs index 33e79f9dc..4300b2138 100644 --- a/src/models/mod.rs +++ b/src/models/mod.rs @@ -12,11 +12,10 @@ pub mod set; pub use algebraic::{ClosestVectorProblem, BMF, ILP, QUBO}; pub use formula::{CNFClause, CircuitSAT, KSatisfiability, Satisfiability}; pub use graph::{ - BicliqueCover, GraphPartitioning, KColoring, MaxCut, MaximalIS, MaximumClique, + BicliqueCover, GraphPartitioning, HamiltonianPath, KColoring, MaxCut, MaximalIS, MaximumClique, MaximumIndependentSet, MaximumMatching, MinimumDominatingSet, MinimumFeedbackArcSet, - MinimumSumMulticenter, - MinimumFeedbackVertexSet, MinimumVertexCover, PartitionIntoTriangles, RuralPostman, SpinGlass, - SubgraphIsomorphism, TravelingSalesman, + MinimumFeedbackVertexSet, MinimumSumMulticenter, MinimumVertexCover, PartitionIntoTriangles, + RuralPostman, SpinGlass, SubgraphIsomorphism, TravelingSalesman, }; pub use misc::{BinPacking, Factoring, Knapsack, LongestCommonSubsequence, PaintShop, SubsetSum}; pub use set::{MaximumSetPacking, MinimumSetCovering}; diff --git a/src/unit_tests/models/graph/hamiltonian_path.rs b/src/unit_tests/models/graph/hamiltonian_path.rs new file mode 100644 index 000000000..fcb2d167a --- /dev/null +++ b/src/unit_tests/models/graph/hamiltonian_path.rs @@ -0,0 +1,140 @@ +use super::*; +use crate::solvers::{BruteForce, Solver}; +use crate::topology::SimpleGraph; + +#[test] +fn test_hamiltonian_path_basic() { + use crate::traits::Problem; + + // Path graph: 0-1-2-3 (has Hamiltonian path) + let problem = HamiltonianPath::new(SimpleGraph::new(4, vec![(0, 1), (1, 2), (2, 3)])); + assert_eq!(problem.num_vertices(), 4); + assert_eq!(problem.num_edges(), 3); + assert_eq!(problem.dims(), vec![4, 4, 4, 4]); + + // Valid path: 0->1->2->3 + assert!(problem.evaluate(&[0, 1, 2, 3])); + // Valid path: 3->2->1->0 (reversed) + assert!(problem.evaluate(&[3, 2, 1, 0])); + // Invalid: 0->1->3->2 (no edge 1-3) + assert!(!problem.evaluate(&[0, 1, 3, 2])); + // Invalid: not a permutation (repeated vertex) + assert!(!problem.evaluate(&[0, 1, 1, 2])); +} + +#[test] +fn test_hamiltonian_path_no_solution() { + // K4 on {0,1,2,3} + two isolated vertices {4,5} + let problem = HamiltonianPath::new(SimpleGraph::new( + 6, + vec![(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)], + )); + let solver = BruteForce::new(); + let solution = solver.find_satisfying(&problem); + assert!( + solution.is_none(), + "Graph with isolated vertices has no Hamiltonian path" + ); +} + +#[test] +fn test_hamiltonian_path_brute_force() { + use crate::traits::Problem; + + // Path graph P4: 0-1-2-3 + let problem = HamiltonianPath::new(SimpleGraph::new(4, vec![(0, 1), (1, 2), (2, 3)])); + let solver = BruteForce::new(); + + let solution = solver.find_satisfying(&problem); + assert!(solution.is_some()); + assert!(problem.evaluate(&solution.unwrap())); + + let all = solver.find_all_satisfying(&problem); + // Path graph P4 has exactly 2 Hamiltonian paths: 0-1-2-3 and 3-2-1-0 + assert_eq!(all.len(), 2); + for sol in &all { + assert!(problem.evaluate(sol)); + } +} + +#[test] +fn test_hamiltonian_path_nontrivial() { + use crate::traits::Problem; + + // Instance 2 from issue: 6 vertices, 8 edges + let problem = HamiltonianPath::new(SimpleGraph::new( + 6, + vec![ + (0, 1), + (0, 2), + (1, 3), + (2, 3), + (3, 4), + (3, 5), + (4, 2), + (5, 1), + ], + )); + // Hamiltonian path: 0->2->4->3->1->5 + assert!(problem.evaluate(&[0, 2, 4, 3, 1, 5])); +} + +#[test] +fn test_hamiltonian_path_complete_graph() { + // Complete graph K4: every permutation is a Hamiltonian path + let problem = HamiltonianPath::new(SimpleGraph::new( + 4, + vec![(0, 1), (0, 2), (0, 3), (1, 2), (1, 3), (2, 3)], + )); + let solver = BruteForce::new(); + let all = solver.find_all_satisfying(&problem); + // K4 has 4! = 24 Hamiltonian paths (all permutations) + assert_eq!(all.len(), 24); +} + +#[test] +fn test_is_valid_hamiltonian_path_function() { + let graph = SimpleGraph::new(4, vec![(0, 1), (1, 2), (2, 3)]); + assert!(is_valid_hamiltonian_path(&graph, &[0, 1, 2, 3])); + assert!(is_valid_hamiltonian_path(&graph, &[3, 2, 1, 0])); + assert!(!is_valid_hamiltonian_path(&graph, &[0, 1, 3, 2])); + // Wrong length + assert!(!is_valid_hamiltonian_path(&graph, &[0, 1, 2])); + // Vertex out of range + assert!(!is_valid_hamiltonian_path(&graph, &[0, 1, 2, 4])); +} + +#[test] +fn test_hamiltonian_path_serialization() { + let problem = HamiltonianPath::new(SimpleGraph::new(3, vec![(0, 1), (1, 2)])); + let json = serde_json::to_value(&problem).unwrap(); + let deserialized: HamiltonianPath = serde_json::from_value(json).unwrap(); + assert_eq!(deserialized.num_vertices(), 3); + assert_eq!(deserialized.num_edges(), 2); +} + +#[test] +fn test_is_valid_solution() { + let problem = HamiltonianPath::new(SimpleGraph::new(3, vec![(0, 1), (1, 2)])); + assert!(problem.is_valid_solution(&[0, 1, 2])); + assert!(!problem.is_valid_solution(&[0, 2, 1])); // no edge 0-2 +} + +#[test] +fn test_size_getters() { + let problem = HamiltonianPath::new(SimpleGraph::new(5, vec![(0, 1), (1, 2), (2, 3), (3, 4)])); + assert_eq!(problem.num_vertices(), 5); + assert_eq!(problem.num_edges(), 4); +} + +#[test] +fn test_single_vertex() { + use crate::traits::Problem; + + // Single vertex graph: trivially has a Hamiltonian "path" (just the vertex) + let problem = HamiltonianPath::new(SimpleGraph::new(1, vec![])); + assert!(problem.evaluate(&[0])); + let solver = BruteForce::new(); + let all = solver.find_all_satisfying(&problem); + assert_eq!(all.len(), 1); +} diff --git a/src/unit_tests/trait_consistency.rs b/src/unit_tests/trait_consistency.rs index cdbdba7a1..91754a81d 100644 --- a/src/unit_tests/trait_consistency.rs +++ b/src/unit_tests/trait_consistency.rs @@ -94,6 +94,10 @@ fn test_all_problems_implement_trait_correctly() { &MinimumSumMulticenter::new(SimpleGraph::new(3, vec![(0, 1), (1, 2)]), vec![1i32; 3], vec![1i32; 2], 1), "MinimumSumMulticenter", ); + check_problem_trait( + &HamiltonianPath::new(SimpleGraph::new(3, vec![(0, 1), (1, 2)])), + "HamiltonianPath", + ); } #[test] diff --git a/tests/suites/examples.rs b/tests/suites/examples.rs index f5a1233e9..c405b28ed 100644 --- a/tests/suites/examples.rs +++ b/tests/suites/examples.rs @@ -10,6 +10,7 @@ macro_rules! example_test { }; } +example_test!(hamiltonian_path); example_test!(chained_reduction_factoring_to_spinglass); example_test!(chained_reduction_ksat_to_mis); example_test!(reduction_binpacking_to_ilp); @@ -64,6 +65,7 @@ macro_rules! example_fn { }; } +example_fn!(test_hamiltonian_path, hamiltonian_path); example_fn!( test_chained_reduction_factoring_to_spinglass, chained_reduction_factoring_to_spinglass