conspire/math/optimize/
mod.rs

1#[cfg(test)]
2mod test;
3
4mod constraint;
5mod gradient_descent;
6mod newton_raphson;
7
8use crate::{
9    defeat_message,
10    math::{
11        TestError,
12        integrate::IntegrationError,
13        matrix::square::{Banded, SquareMatrixError},
14    },
15};
16use std::fmt::{self, Debug, Display, Formatter};
17
18pub use constraint::EqualityConstraint;
19pub use gradient_descent::GradientDescent;
20pub use newton_raphson::NewtonRaphson;
21
22/// Zeroth-order root-finding algorithms.
23pub trait ZerothOrderRootFinding<X> {
24    fn root(
25        &self,
26        function: impl Fn(&X) -> Result<X, OptimizeError>,
27        initial_guess: X,
28        equality_constraint: EqualityConstraint,
29    ) -> Result<X, OptimizeError>;
30}
31
32/// First-order root-finding algorithms.
33pub trait FirstOrderRootFinding<F, J, X> {
34    fn root(
35        &self,
36        function: impl Fn(&X) -> Result<F, OptimizeError>,
37        jacobian: impl Fn(&X) -> Result<J, OptimizeError>,
38        initial_guess: X,
39        equality_constraint: EqualityConstraint,
40    ) -> Result<X, OptimizeError>;
41}
42
43/// First-order optimization algorithms.
44pub trait FirstOrderOptimization<F, X> {
45    fn minimize(
46        &self,
47        function: impl Fn(&X) -> Result<F, OptimizeError>,
48        jacobian: impl Fn(&X) -> Result<X, OptimizeError>,
49        initial_guess: X,
50        equality_constraint: EqualityConstraint,
51    ) -> Result<X, OptimizeError>;
52}
53
54/// Second-order optimization algorithms.
55pub trait SecondOrderOptimization<F, H, J, X> {
56    fn minimize(
57        &self,
58        function: impl Fn(&X) -> Result<F, OptimizeError>,
59        jacobian: impl Fn(&X) -> Result<J, OptimizeError>,
60        hessian: impl Fn(&X) -> Result<H, OptimizeError>,
61        initial_guess: X,
62        equality_constraint: EqualityConstraint,
63        banded: Option<Banded>,
64    ) -> Result<X, OptimizeError>;
65}
66
67/// Possible optimization algorithms.
68#[derive(Debug)]
69pub enum Optimization {
70    GradientDescent(GradientDescent),
71    NewtonRaphson(NewtonRaphson),
72}
73
74/// Possible errors encountered when optimizing.
75pub enum OptimizeError {
76    Generic(String),
77    MaximumStepsReached(usize, String),
78    NotMinimum(String, String),
79    SingularMatrix,
80}
81
82impl From<OptimizeError> for TestError {
83    fn from(error: OptimizeError) -> Self {
84        Self {
85            message: error.to_string(),
86        }
87    }
88}
89
90impl From<IntegrationError> for OptimizeError {
91    fn from(_error: IntegrationError) -> Self {
92        todo!()
93    }
94}
95
96impl From<SquareMatrixError> for OptimizeError {
97    fn from(_error: SquareMatrixError) -> Self {
98        Self::SingularMatrix
99    }
100}
101
102impl Debug for OptimizeError {
103    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
104        let error = match self {
105            Self::Generic(message) => message.to_string(),
106            Self::MaximumStepsReached(steps, optimizer) => {
107                format!(
108                    "\x1b[1;91mMaximum number of steps ({}) reached.\x1b[0;91m\n\
109                     In optimizer: {}.",
110                    steps, optimizer
111                )
112            }
113            Self::NotMinimum(solution, optimizer) => {
114                format!(
115                    "\x1b[1;91mThe obtained solution is not a minimum.\x1b[0;91m\n\
116                     For solution: {}.\n\
117                     In optimizer: {}.",
118                    solution, optimizer
119                )
120            }
121            Self::SingularMatrix => "\x1b[1;91mMatrix is singular.".to_string(),
122        };
123        write!(f, "\n{}\n\x1b[0;2;31m{}\x1b[0m\n", error, defeat_message())
124    }
125}
126
127impl Display for OptimizeError {
128    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
129        let error = match self {
130            Self::Generic(message) => message.to_string(),
131            Self::MaximumStepsReached(steps, optimizer) => {
132                format!(
133                    "\x1b[1;91mMaximum number of steps ({}) reached.\x1b[0;91m\n\
134                     In optimizer: {}.",
135                    steps, optimizer
136                )
137            }
138            Self::NotMinimum(solution, optimizer) => {
139                format!(
140                    "\x1b[1;91mThe obtained solution is not a minimum.\x1b[0;91m\n\
141                     For solution: {}.\n\
142                     In optimizer: {}.",
143                    solution, optimizer
144                )
145            }
146            Self::SingularMatrix => "\x1b[1;91mMatrix is singular.".to_string(),
147        };
148        write!(f, "{}\x1b[0m", error)
149    }
150}