problemreductions/registry/info.rs
1//! Problem metadata and information types.
2//!
3//! This module provides types for describing problem characteristics:
4//!
5//! - [`ComplexityClass`] - Computational complexity (P, NP-complete, etc.)
6//! - [`ProblemInfo`] - Rich metadata about a problem type
7//! - [`ProblemMetadata`] - Trait for problems to provide their metadata
8//!
9//! # Example
10//!
11//! ```rust
12//! use problemreductions::registry::{ProblemInfo, ComplexityClass};
13//!
14//! let info = ProblemInfo::new("3-SAT", "Satisfiability with 3-literal clauses")
15//! .with_aliases(&["3-CNF-SAT", "3SAT"])
16//! .with_complexity(ComplexityClass::NpComplete)
17//! .with_reduction_from("SAT");
18//!
19//! assert!(info.is_np_complete());
20//! assert_eq!(info.all_names().len(), 3);
21//! ```
22
23use std::fmt;
24
25/// Computational complexity class of a problem.
26///
27/// Used to classify problems by their computational difficulty.
28/// Most problems in this library are [`NpComplete`](ComplexityClass::NpComplete).
29///
30/// # Example
31///
32/// ```rust
33/// use problemreductions::registry::ComplexityClass;
34///
35/// let class = ComplexityClass::NpComplete;
36/// assert!(class.is_hard());
37/// assert_eq!(class.name(), "NP-complete");
38/// ```
39#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
40pub enum ComplexityClass {
41 /// In P (polynomial time)
42 P,
43 /// NP-complete
44 NpComplete,
45 /// NP-hard (at least as hard as NP-complete)
46 NpHard,
47 /// PSPACE-complete
48 PspaceComplete,
49 /// Unknown or unclassified
50 Unknown,
51}
52
53impl ComplexityClass {
54 /// Get the complexity class name.
55 pub fn name(&self) -> &'static str {
56 match self {
57 ComplexityClass::P => "P",
58 ComplexityClass::NpComplete => "NP-complete",
59 ComplexityClass::NpHard => "NP-hard",
60 ComplexityClass::PspaceComplete => "PSPACE-complete",
61 ComplexityClass::Unknown => "Unknown",
62 }
63 }
64
65 /// Check if this problem is at least NP-hard.
66 pub fn is_hard(&self) -> bool {
67 matches!(
68 self,
69 ComplexityClass::NpComplete | ComplexityClass::NpHard | ComplexityClass::PspaceComplete
70 )
71 }
72}
73
74impl fmt::Display for ComplexityClass {
75 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
76 write!(f, "{}", self.name())
77 }
78}
79
80/// Metadata about a problem type.
81///
82/// Contains static information about a problem definition, including its name,
83/// description, complexity class, and relationships to other problems.
84/// Use the builder methods to construct instances.
85///
86/// # Example
87///
88/// ```rust
89/// use problemreductions::registry::{ProblemInfo, ComplexityClass};
90///
91/// let info = ProblemInfo::new("Vertex Cover", "Find minimum vertices covering all edges")
92/// .with_aliases(&["VC", "Minimum Vertex Cover"])
93/// .with_complexity(ComplexityClass::NpComplete)
94/// .with_reduction_from("Independent Set")
95/// .with_reference("https://en.wikipedia.org/wiki/Vertex_cover");
96///
97/// println!("{}", info); // "Vertex Cover (NP-complete)"
98/// ```
99///
100/// # Builder Pattern
101///
102/// All builder methods are `const fn` and can be used in const contexts:
103///
104/// ```rust
105/// use problemreductions::registry::{ProblemInfo, ComplexityClass};
106///
107/// const MY_PROBLEM_INFO: ProblemInfo = ProblemInfo::new("My Problem", "Description")
108/// .with_complexity(ComplexityClass::NpComplete);
109/// ```
110#[derive(Debug, Clone, PartialEq, Eq)]
111pub struct ProblemInfo {
112 /// The canonical name of the problem.
113 pub name: &'static str,
114 /// Alternative names for the problem.
115 pub aliases: &'static [&'static str],
116 /// A brief description of the problem.
117 pub description: &'static str,
118 /// The computational complexity class.
119 pub complexity_class: ComplexityClass,
120 /// Whether this has a decision version (yes/no answer).
121 pub decision_version: bool,
122 /// Whether this has an optimization version.
123 pub optimization_version: bool,
124 /// The canonical problem this reduces from (for NP-completeness proof).
125 pub canonical_reduction_from: Option<&'static str>,
126 /// Wikipedia or reference URL.
127 pub reference_url: Option<&'static str>,
128 /// Struct field descriptions for schema export.
129 pub fields: &'static [FieldInfo],
130}
131
132impl ProblemInfo {
133 /// Create a new ProblemInfo with minimal required fields.
134 pub const fn new(name: &'static str, description: &'static str) -> Self {
135 Self {
136 name,
137 aliases: &[],
138 description,
139 complexity_class: ComplexityClass::NpComplete,
140 decision_version: true,
141 optimization_version: true,
142 canonical_reduction_from: None,
143 reference_url: None,
144 fields: &[],
145 }
146 }
147
148 /// Builder method to add aliases.
149 pub const fn with_aliases(mut self, aliases: &'static [&'static str]) -> Self {
150 self.aliases = aliases;
151 self
152 }
153
154 /// Builder method to set complexity class.
155 pub const fn with_complexity(mut self, class: ComplexityClass) -> Self {
156 self.complexity_class = class;
157 self
158 }
159
160 /// Builder method to set decision version availability.
161 pub const fn with_decision(mut self, has_decision: bool) -> Self {
162 self.decision_version = has_decision;
163 self
164 }
165
166 /// Builder method to set optimization version availability.
167 pub const fn with_optimization(mut self, has_optimization: bool) -> Self {
168 self.optimization_version = has_optimization;
169 self
170 }
171
172 /// Builder method to set the canonical reduction source.
173 pub const fn with_reduction_from(mut self, source: &'static str) -> Self {
174 self.canonical_reduction_from = Some(source);
175 self
176 }
177
178 /// Builder method to set reference URL.
179 pub const fn with_reference(mut self, url: &'static str) -> Self {
180 self.reference_url = Some(url);
181 self
182 }
183
184 /// Builder method to set struct field descriptions.
185 pub const fn with_fields(mut self, fields: &'static [FieldInfo]) -> Self {
186 self.fields = fields;
187 self
188 }
189
190 /// Check if this problem is NP-complete.
191 pub fn is_np_complete(&self) -> bool {
192 self.complexity_class == ComplexityClass::NpComplete
193 }
194
195 /// Get all names (canonical + aliases).
196 pub fn all_names(&self) -> Vec<&'static str> {
197 let mut names = vec![self.name];
198 names.extend_from_slice(self.aliases);
199 names
200 }
201}
202
203impl fmt::Display for ProblemInfo {
204 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
205 write!(f, "{} ({})", self.name, self.complexity_class)
206 }
207}
208
209/// Description of a struct field for JSON schema export.
210#[derive(Debug, Clone, PartialEq, Eq)]
211pub struct FieldInfo {
212 /// Field name as it appears in the Rust struct.
213 pub name: &'static str,
214 /// Type name (e.g., `Vec<W>`, `UnGraph<(), ()>`).
215 pub type_name: &'static str,
216 /// Human-readable description of what this field represents.
217 pub description: &'static str,
218}
219
220/// Trait for problems that provide static metadata.
221///
222/// Implement this trait to enable introspection and discovery for problem types.
223///
224/// # Example
225///
226/// ```rust
227/// use problemreductions::registry::{
228/// ProblemMetadata, ProblemInfo, ComplexityClass
229/// };
230///
231/// struct MyProblem;
232///
233/// impl ProblemMetadata for MyProblem {
234/// fn problem_info() -> ProblemInfo {
235/// ProblemInfo::new("My Problem", "Description")
236/// .with_complexity(ComplexityClass::NpComplete)
237/// }
238/// }
239///
240/// // Get problem metadata
241/// let info = MyProblem::problem_info();
242/// assert_eq!(info.name, "My Problem");
243/// ```
244pub trait ProblemMetadata {
245 /// Returns the problem info for this problem type.
246 ///
247 /// This includes the problem name, description, aliases, complexity class,
248 /// and known reductions.
249 fn problem_info() -> ProblemInfo;
250}
251
252#[cfg(test)]
253#[path = "../unit_tests/registry/info.rs"]
254mod tests;