Skip to main content

problemreductions/registry/
problem_type.rs

1//! Problem type catalog: runtime lookup by name, alias, and variant validation.
2
3use super::schema::{ProblemCategory, ProblemSchemaEntry, VariantDimension};
4use super::FieldInfo;
5use std::collections::BTreeMap;
6
7/// A runtime view of a registered problem type from the catalog.
8#[derive(Debug, Clone)]
9pub struct ProblemType {
10    /// Canonical problem name (e.g., `"MaximumIndependentSet"`).
11    pub canonical_name: &'static str,
12    /// Human-readable display name (e.g., `"Maximum Independent Set"`).
13    pub display_name: &'static str,
14    /// Short aliases (e.g., `["MIS"]`).
15    pub aliases: &'static [&'static str],
16    /// Declared variant dimensions with defaults and allowed values.
17    pub dimensions: &'static [VariantDimension],
18    /// Human-readable description.
19    pub description: &'static str,
20    /// Inputs accepted when constructing this problem.
21    pub fields: &'static [FieldInfo],
22    /// Explicit structural model category.
23    pub category: ProblemCategory,
24}
25
26impl ProblemType {
27    /// Build a `ProblemType` view from a schema entry.
28    fn from_entry(entry: &'static ProblemSchemaEntry) -> Self {
29        Self {
30            canonical_name: entry.name,
31            display_name: entry.display_name,
32            aliases: entry.aliases,
33            dimensions: entry.dimensions,
34            description: entry.description,
35            fields: entry.fields,
36            category: entry.category,
37        }
38    }
39
40    /// Get the default variant map (each dimension set to its default value).
41    pub fn default_variant(&self) -> BTreeMap<String, String> {
42        self.dimensions
43            .iter()
44            .map(|d| (d.key.to_string(), d.default_value.to_string()))
45            .collect()
46    }
47}
48
49/// Find a problem type by exact canonical name.
50pub fn find_problem_type(name: &str) -> Option<ProblemType> {
51    inventory::iter::<ProblemSchemaEntry>
52        .into_iter()
53        .find(|entry| entry.name == name)
54        .map(ProblemType::from_entry)
55}
56
57/// Find a problem type by alias (case-insensitive).
58///
59/// Searches both canonical names and declared aliases.
60pub fn find_problem_type_by_alias(input: &str) -> Option<ProblemType> {
61    let lower = input.to_lowercase();
62    inventory::iter::<ProblemSchemaEntry>
63        .into_iter()
64        .find(|entry| {
65            entry.name.to_lowercase() == lower
66                || entry.aliases.iter().any(|a| a.to_lowercase() == lower)
67        })
68        .map(ProblemType::from_entry)
69}
70
71/// Return all registered problem types.
72pub fn problem_types() -> Vec<ProblemType> {
73    let mut types: Vec<ProblemType> = inventory::iter::<ProblemSchemaEntry>
74        .into_iter()
75        .map(ProblemType::from_entry)
76        .collect();
77    types.sort_by_key(|t| t.canonical_name);
78    types
79}
80
81#[cfg(test)]
82#[path = "../unit_tests/registry/problem_type.rs"]
83mod tests;