problemreductions/variant.rs
1//! Variant system for type-level problem parameterization.
2//!
3//! Types declare their variant category, value, and parent via `VariantParam`.
4//! The `impl_variant_param!` macro registers types with the trait.
5//! The `variant_params!` macro composes `Problem::variant()` bodies from type parameter names.
6
7/// A type that participates in the variant system.
8///
9/// Declares its category (e.g., `"graph"`), value (e.g., `"SimpleGraph"`),
10/// and optional parent in the subtype hierarchy.
11pub trait VariantParam: 'static {
12 /// Category name (e.g., `"graph"`, `"weight"`, `"k"`).
13 const CATEGORY: &'static str;
14 /// Type name within the category (e.g., `"SimpleGraph"`, `"i32"`).
15 const VALUE: &'static str;
16 /// Parent type name in the subtype hierarchy, or `None` for root types.
17 const PARENT_VALUE: Option<&'static str>;
18}
19
20/// Types that can convert themselves to their parent in the variant hierarchy.
21pub trait CastToParent: VariantParam {
22 /// The parent type.
23 type Parent: VariantParam;
24 /// Convert this value to its parent type.
25 fn cast_to_parent(&self) -> Self::Parent;
26}
27
28/// K-value marker trait for types that represent a const-generic K parameter.
29///
30/// Types implementing this trait declare an optional K value. `None` means
31/// the type represents an arbitrary K (like KN), while `Some(k)` means
32/// a specific value (like K2, K3).
33pub trait KValue: VariantParam + Clone + 'static {
34 /// The K value, or `None` for arbitrary K.
35 const K: Option<usize>;
36}
37
38/// Implement `VariantParam` (and optionally `CastToParent` and/or `KValue`) for a type.
39///
40/// # Usage
41///
42/// ```text
43/// // Root type (no parent):
44/// impl_variant_param!(SimpleGraph, "graph");
45///
46/// // Type with parent -- cast closure required:
47/// impl_variant_param!(UnitDiskGraph, "graph", parent: SimpleGraph,
48/// cast: |g| SimpleGraph::new(g.num_vertices(), g.edges()));
49///
50/// // Root K type (no parent, with K value):
51/// impl_variant_param!(KN, "k", k: None);
52///
53/// // K type with parent + cast + K value:
54/// impl_variant_param!(K3, "k", parent: KN, cast: |_| KN, k: Some(3));
55/// ```
56#[macro_export]
57macro_rules! impl_variant_param {
58 // Root type (no parent, no cast)
59 ($ty:ty, $cat:expr) => {
60 impl $crate::variant::VariantParam for $ty {
61 const CATEGORY: &'static str = $cat;
62 const VALUE: &'static str = stringify!($ty);
63 const PARENT_VALUE: Option<&'static str> = None;
64 }
65 };
66 // Type with parent + cast closure
67 ($ty:ty, $cat:expr, parent: $parent:ty, cast: $cast:expr) => {
68 impl $crate::variant::VariantParam for $ty {
69 const CATEGORY: &'static str = $cat;
70 const VALUE: &'static str = stringify!($ty);
71 const PARENT_VALUE: Option<&'static str> = Some(stringify!($parent));
72 }
73 impl $crate::variant::CastToParent for $ty {
74 type Parent = $parent;
75 fn cast_to_parent(&self) -> $parent {
76 let f: fn(&$ty) -> $parent = $cast;
77 f(self)
78 }
79 }
80 };
81 // KValue root type (no parent, with k value)
82 ($ty:ty, $cat:expr, k: $k:expr) => {
83 $crate::impl_variant_param!($ty, $cat);
84 impl $crate::variant::KValue for $ty {
85 const K: Option<usize> = $k;
86 }
87 };
88 // KValue type with parent + cast + k value
89 ($ty:ty, $cat:expr, parent: $parent:ty, cast: $cast:expr, k: $k:expr) => {
90 $crate::impl_variant_param!($ty, $cat, parent: $parent, cast: $cast);
91 impl $crate::variant::KValue for $ty {
92 const K: Option<usize> = $k;
93 }
94 };
95}
96
97/// Compose a `Problem::variant()` body from type parameter names.
98///
99/// All variant dimensions must be types implementing `VariantParam`.
100///
101/// # Usage
102///
103/// ```text
104/// variant_params![] // -> vec![]
105/// variant_params![G, W] // -> vec![(G::CATEGORY, G::VALUE), ...]
106/// ```
107#[macro_export]
108macro_rules! variant_params {
109 () => { vec![] };
110 ($($T:ident),+) => {
111 vec![$((<$T as $crate::variant::VariantParam>::CATEGORY,
112 <$T as $crate::variant::VariantParam>::VALUE)),+]
113 };
114}
115
116// --- Concrete KValue types ---
117
118/// K=1 (e.g., 1-coloring).
119#[derive(Clone, Copy, Debug, Default)]
120pub struct K1;
121
122/// K=2 (e.g., 2-SAT, 2-coloring).
123#[derive(Clone, Copy, Debug, Default)]
124pub struct K2;
125
126/// K=3 (e.g., 3-SAT, 3-coloring).
127#[derive(Clone, Copy, Debug, Default)]
128pub struct K3;
129
130/// K=4 (e.g., 4-coloring).
131#[derive(Clone, Copy, Debug, Default)]
132pub struct K4;
133
134/// K=5 (e.g., 5-coloring).
135#[derive(Clone, Copy, Debug, Default)]
136pub struct K5;
137
138/// Generic K (any value). Used for reductions that apply to all K.
139#[derive(Clone, Copy, Debug, Default)]
140pub struct KN;
141
142impl_variant_param!(KN, "k", k: None);
143impl_variant_param!(K5, "k", parent: KN, cast: |_| KN, k: Some(5));
144impl_variant_param!(K4, "k", parent: KN, cast: |_| KN, k: Some(4));
145impl_variant_param!(K3, "k", parent: KN, cast: |_| KN, k: Some(3));
146impl_variant_param!(K2, "k", parent: KN, cast: |_| KN, k: Some(2));
147impl_variant_param!(K1, "k", parent: KN, cast: |_| KN, k: Some(1));
148
149#[cfg(test)]
150#[path = "unit_tests/variant.rs"]
151mod tests;