Skip to main content

problemreductions/registry/
mod.rs

1//! Problem registry and metadata types.
2//!
3//! This module provides types for problem introspection and discovery.
4//!
5//! # Overview
6//!
7//! - [`ProblemInfo`] - Rich metadata (name, description, complexity, reductions)
8//! - [`ProblemMetadata`] - Trait for problems to provide their own metadata
9//! - [`ComplexityClass`] - Computational complexity classification
10//!
11//! # Example
12//!
13//! ```rust
14//! use problemreductions::registry::{ProblemInfo, ComplexityClass};
15//!
16//! // Create problem metadata
17//! let info = ProblemInfo::new("Independent Set", "Find maximum non-adjacent vertices")
18//!     .with_aliases(&["MIS", "Stable Set"])
19//!     .with_complexity(ComplexityClass::NpComplete)
20//!     .with_reduction_from("3-SAT");
21//!
22//! assert!(info.is_np_complete());
23//! ```
24//!
25//! # Implementing for Custom Problems
26//!
27//! Problems can implement [`ProblemMetadata`] to provide introspection:
28//!
29//! ```rust
30//! use problemreductions::registry::{
31//!     ProblemMetadata, ProblemInfo, ComplexityClass
32//! };
33//!
34//! struct MyProblem;
35//!
36//! impl ProblemMetadata for MyProblem {
37//!     fn problem_info() -> ProblemInfo {
38//!         ProblemInfo::new("My Problem", "Description")
39//!             .with_complexity(ComplexityClass::NpComplete)
40//!     }
41//! }
42//!
43//! let info = MyProblem::problem_info();
44//! println!("Problem: {}", info.name);
45//! ```
46
47mod dyn_problem;
48mod info;
49pub mod problem_ref;
50pub mod problem_type;
51mod schema;
52pub mod variant;
53
54pub use dyn_problem::{format_metric, DynProblem, LoadedDynProblem, SolveValueFn, SolveWitnessFn};
55pub use info::{ComplexityClass, FieldInfo, ProblemInfo, ProblemMetadata};
56pub use problem_ref::{parse_catalog_problem_ref, require_graph_variant, ProblemRef};
57pub use problem_type::{find_problem_type, find_problem_type_by_alias, problem_types, ProblemType};
58pub use schema::{
59    collect_schemas, declared_size_fields, FieldInfoJson, ProblemSchemaEntry, ProblemSchemaJson,
60    ProblemSizeFieldEntry, VariantDimension,
61};
62pub use variant::{
63    find_variant_by_alias, find_variant_entry, validate_variant_aliases, VariantEntry,
64};
65
66use std::any::Any;
67use std::collections::BTreeMap;
68
69/// Load a problem from JSON by exact problem name and exact variant map.
70///
71/// No alias resolution or default fallback. Returns `Err` if the entry is not found.
72pub fn load_dyn(
73    name: &str,
74    variant: &BTreeMap<String, String>,
75    data: serde_json::Value,
76) -> Result<LoadedDynProblem, String> {
77    let entry = find_variant_entry(name, variant).ok_or_else(|| {
78        format!(
79            "No registered variant for `{name}` with variant {:?}",
80            variant
81        )
82    })?;
83
84    let inner =
85        (entry.factory)(data).map_err(|e| format!("Failed to deserialize `{name}`: {e}"))?;
86    Ok(LoadedDynProblem::new(
87        inner,
88        entry.solve_value_fn,
89        entry.solve_witness_fn,
90    ))
91}
92
93/// Serialize a `&dyn Any` by exact problem name and exact variant map.
94///
95/// Returns `None` if the entry is not found or the downcast fails.
96pub fn serialize_any(
97    name: &str,
98    variant: &BTreeMap<String, String>,
99    any: &dyn Any,
100) -> Option<serde_json::Value> {
101    let entry = find_variant_entry(name, variant)?;
102    (entry.serialize_fn)(any)
103}
104
105#[cfg(test)]
106#[path = "../unit_tests/registry/dispatch.rs"]
107mod dispatch_tests;