amari_optimization/
phantom.rs

1//! # Phantom Types for Optimization State
2//!
3//! This module provides phantom types that encode optimization problem properties
4//! at compile time, ensuring type safety and preventing invalid operations.
5//!
6//! ## Mathematical Background
7//!
8//! Optimization problems can be characterized by several properties:
9//! - **Constraints**: Whether the problem has constraints or is unconstrained
10//! - **Objectives**: Single-objective vs multi-objective optimization
11//! - **Convexity**: Whether the problem is convex or non-convex
12//! - **Manifold**: Whether optimization occurs on a manifold
13//!
14//! These properties affect which optimization algorithms are applicable and
15//! what guarantees can be made about convergence.
16
17use std::marker::PhantomData;
18
19/// Marker trait for constraint states
20pub trait ConstraintState {}
21
22/// Marker trait for objective states
23pub trait ObjectiveState {}
24
25/// Marker trait for convexity states
26pub trait ConvexityState {}
27
28/// Marker trait for manifold states
29pub trait ManifoldState {}
30
31/// Optimization problem is unconstrained
32#[derive(Clone, Copy, Debug)]
33pub struct Unconstrained;
34
35/// Optimization problem has constraints
36#[derive(Clone, Copy, Debug)]
37pub struct Constrained;
38
39/// Optimization is single-objective
40#[derive(Clone, Copy, Debug)]
41pub struct SingleObjective;
42
43/// Optimization is multi-objective
44#[derive(Clone, Copy, Debug)]
45pub struct MultiObjective;
46
47/// Problem is convex
48#[derive(Clone, Copy, Debug)]
49pub struct Convex;
50
51/// Problem is non-convex
52#[derive(Clone, Copy, Debug)]
53pub struct NonConvex;
54
55/// Optimization on Euclidean space
56#[derive(Clone, Copy, Debug)]
57pub struct Euclidean;
58
59/// Optimization on a Riemannian manifold
60#[derive(Clone, Copy, Debug)]
61pub struct Riemannian;
62
63/// Optimization on a statistical manifold (information geometry)
64#[derive(Clone, Copy, Debug)]
65pub struct Statistical;
66
67// Implement marker traits
68impl ConstraintState for Unconstrained {}
69impl ConstraintState for Constrained {}
70
71impl ObjectiveState for SingleObjective {}
72impl ObjectiveState for MultiObjective {}
73
74impl ConvexityState for Convex {}
75impl ConvexityState for NonConvex {}
76
77impl ManifoldState for Euclidean {}
78impl ManifoldState for Riemannian {}
79impl ManifoldState for Statistical {}
80
81/// Optimization problem with compile-time properties
82///
83/// This type encodes optimization problem characteristics at compile time,
84/// enabling the type system to enforce correct usage of optimization algorithms.
85///
86/// # Type Parameters
87///
88/// * `DIM` - Problem dimension (number of parameters)
89/// * `C` - Constraint state (Unconstrained or Constrained)
90/// * `O` - Objective state (SingleObjective or MultiObjective)
91/// * `V` - Convexity state (Convex or NonConvex)
92/// * `M` - Manifold state (Euclidean, Riemannian, or Statistical)
93///
94/// # Examples
95///
96/// ```rust
97/// use amari_optimization::phantom::*;
98///
99/// // Unconstrained, single-objective, convex problem in Euclidean space
100/// type ConvexProblem = OptimizationProblem<10, Unconstrained, SingleObjective, Convex, Euclidean>;
101///
102/// // Multi-objective problem on a statistical manifold
103/// type MultiObjectiveStats = OptimizationProblem<5, Unconstrained, MultiObjective, NonConvex, Statistical>;
104/// ```
105#[derive(Clone, Debug)]
106pub struct OptimizationProblem<
107    const DIM: usize,
108    C: ConstraintState = Unconstrained,
109    O: ObjectiveState = SingleObjective,
110    V: ConvexityState = NonConvex,
111    M: ManifoldState = Euclidean,
112> {
113    _constraint: PhantomData<C>,
114    _objective: PhantomData<O>,
115    _convexity: PhantomData<V>,
116    _manifold: PhantomData<M>,
117}
118
119impl<
120        const DIM: usize,
121        C: ConstraintState,
122        O: ObjectiveState,
123        V: ConvexityState,
124        M: ManifoldState,
125    > OptimizationProblem<DIM, C, O, V, M>
126{
127    /// Create a new optimization problem with given properties
128    pub fn new() -> Self {
129        Self {
130            _constraint: PhantomData,
131            _objective: PhantomData,
132            _convexity: PhantomData,
133            _manifold: PhantomData,
134        }
135    }
136
137    /// Get the problem dimension
138    pub const fn dimension(&self) -> usize {
139        DIM
140    }
141}
142
143impl<
144        const DIM: usize,
145        C: ConstraintState,
146        O: ObjectiveState,
147        V: ConvexityState,
148        M: ManifoldState,
149    > Default for OptimizationProblem<DIM, C, O, V, M>
150{
151    fn default() -> Self {
152        Self::new()
153    }
154}
155
156// Type state transitions - these allow changing problem properties while maintaining type safety
157
158impl<const DIM: usize, O: ObjectiveState, V: ConvexityState, M: ManifoldState>
159    OptimizationProblem<DIM, Unconstrained, O, V, M>
160{
161    /// Add constraints to an unconstrained problem
162    pub fn with_constraints(self) -> OptimizationProblem<DIM, Constrained, O, V, M> {
163        OptimizationProblem::new()
164    }
165}
166
167impl<const DIM: usize, C: ConstraintState, V: ConvexityState, M: ManifoldState>
168    OptimizationProblem<DIM, C, SingleObjective, V, M>
169{
170    /// Convert to multi-objective problem
171    pub fn with_multiple_objectives(self) -> OptimizationProblem<DIM, C, MultiObjective, V, M> {
172        OptimizationProblem::new()
173    }
174}
175
176impl<const DIM: usize, C: ConstraintState, O: ObjectiveState, M: ManifoldState>
177    OptimizationProblem<DIM, C, O, NonConvex, M>
178{
179    /// Mark problem as convex (if verified)
180    pub fn assume_convex(self) -> OptimizationProblem<DIM, C, O, Convex, M> {
181        OptimizationProblem::new()
182    }
183}
184
185impl<const DIM: usize, C: ConstraintState, O: ObjectiveState, V: ConvexityState>
186    OptimizationProblem<DIM, C, O, V, Euclidean>
187{
188    /// Specify optimization on Riemannian manifold
189    pub fn on_riemannian_manifold(self) -> OptimizationProblem<DIM, C, O, V, Riemannian> {
190        OptimizationProblem::new()
191    }
192
193    /// Specify optimization on statistical manifold
194    pub fn on_statistical_manifold(self) -> OptimizationProblem<DIM, C, O, V, Statistical> {
195        OptimizationProblem::new()
196    }
197}
198
199/// Marker trait for algorithms that can handle unconstrained problems
200pub trait HandlesUnconstrained<
201    const DIM: usize,
202    O: ObjectiveState,
203    V: ConvexityState,
204    M: ManifoldState,
205>
206{
207    /// Output type for optimization results
208    type Output;
209
210    /// Optimize an unconstrained problem
211    fn optimize_unconstrained(
212        &self,
213        problem: &OptimizationProblem<DIM, Unconstrained, O, V, M>,
214    ) -> Self::Output;
215}
216
217/// Marker trait for algorithms that can handle constrained problems
218pub trait HandlesConstrained<
219    const DIM: usize,
220    O: ObjectiveState,
221    V: ConvexityState,
222    M: ManifoldState,
223>
224{
225    /// Output type for optimization results
226    type Output;
227
228    /// Optimize a constrained problem
229    fn optimize_constrained(
230        &self,
231        problem: &OptimizationProblem<DIM, Constrained, O, V, M>,
232    ) -> Self::Output;
233}
234
235/// Marker trait for algorithms that require convex problems
236pub trait RequiresConvex<const DIM: usize, C: ConstraintState, O: ObjectiveState, M: ManifoldState>
237{
238    /// Output type for optimization results
239    type Output;
240
241    /// Optimize a convex problem
242    fn optimize_convex(&self, problem: &OptimizationProblem<DIM, C, O, Convex, M>) -> Self::Output;
243}
244
245/// Marker trait for algorithms that can handle multi-objective problems
246pub trait HandlesMultiObjective<
247    const DIM: usize,
248    C: ConstraintState,
249    V: ConvexityState,
250    M: ManifoldState,
251>
252{
253    /// Output type for optimization results
254    type Output;
255
256    /// Optimize a multi-objective problem
257    fn optimize_multiobjective(
258        &self,
259        problem: &OptimizationProblem<DIM, C, MultiObjective, V, M>,
260    ) -> Self::Output;
261}
262
263/// Marker trait for algorithms that work on statistical manifolds
264pub trait HandlesStatistical<
265    const DIM: usize,
266    C: ConstraintState,
267    O: ObjectiveState,
268    V: ConvexityState,
269>
270{
271    /// Output type for optimization results
272    type Output;
273
274    /// Optimize on a statistical manifold
275    fn optimize_statistical(
276        &self,
277        problem: &OptimizationProblem<DIM, C, O, V, Statistical>,
278    ) -> Self::Output;
279}
280
281#[cfg(test)]
282mod tests {
283    use super::*;
284
285    #[test]
286    fn test_problem_creation() {
287        let _problem: OptimizationProblem<
288            10,
289            Unconstrained,
290            SingleObjective,
291            NonConvex,
292            Euclidean,
293        > = OptimizationProblem::new();
294
295        assert_eq!(_problem.dimension(), 10);
296    }
297
298    #[test]
299    fn test_type_state_transitions() {
300        let problem: OptimizationProblem<5, Unconstrained, SingleObjective, NonConvex, Euclidean> =
301            OptimizationProblem::new();
302
303        // Add constraints
304        let _constrained = problem.with_constraints();
305
306        // Make multi-objective
307        let problem =
308            OptimizationProblem::<5, Unconstrained, SingleObjective, NonConvex, Euclidean>::new();
309        let _multiobjective = problem.with_multiple_objectives();
310
311        // Assume convex
312        let problem =
313            OptimizationProblem::<5, Unconstrained, SingleObjective, NonConvex, Euclidean>::new();
314        let _convex = problem.assume_convex();
315
316        // Change manifold
317        let problem =
318            OptimizationProblem::<5, Unconstrained, SingleObjective, NonConvex, Euclidean>::new();
319        let _riemannian = problem.clone().on_riemannian_manifold();
320        let _statistical = problem.on_statistical_manifold();
321    }
322
323    #[test]
324    fn test_default_construction() {
325        let _problem: OptimizationProblem<3> = OptimizationProblem::default();
326        assert_eq!(_problem.dimension(), 3);
327    }
328}