1use nabled_core::errors::{IntoNabledError, NabledError, ShapeError};
39
40use crate::iterative::IterativeError;
41use crate::jacobian::JacobianError;
42use crate::optimization::OptimizationError;
43use crate::pca::PCAError;
44use crate::regression::RegressionError;
45use crate::stats::StatsError;
46
47pub mod iterative;
48pub mod jacobian;
49pub mod optimization;
50pub mod pca;
51pub mod regression;
52pub mod stats;
53
54impl IntoNabledError for IterativeError {
55 fn into_nabled_error(self) -> NabledError {
56 match self {
57 IterativeError::EmptyMatrix => NabledError::Shape(ShapeError::EmptyInput),
58 IterativeError::DimensionMismatch => NabledError::Shape(ShapeError::DimensionMismatch),
59 IterativeError::MaxIterationsExceeded | IterativeError::Breakdown => {
60 NabledError::ConvergenceFailed
61 }
62 IterativeError::NotPositiveDefinite => NabledError::NotPositiveDefinite,
63 }
64 }
65}
66
67impl IntoNabledError for JacobianError {
68 fn into_nabled_error(self) -> NabledError {
69 match self {
70 JacobianError::FunctionError(message) => {
71 NabledError::Other(format!("function error: {message}"))
72 }
73 JacobianError::InvalidDimensions(message) => NabledError::InvalidInput(message),
74 JacobianError::InvalidStepSize => {
75 NabledError::InvalidInput("invalid step size".to_string())
76 }
77 JacobianError::ConvergenceFailed => NabledError::ConvergenceFailed,
78 JacobianError::EmptyInput => NabledError::Shape(ShapeError::EmptyInput),
79 JacobianError::DimensionMismatch => NabledError::Shape(ShapeError::DimensionMismatch),
80 }
81 }
82}
83
84impl IntoNabledError for OptimizationError {
85 fn into_nabled_error(self) -> NabledError {
86 match self {
87 OptimizationError::EmptyInput => NabledError::Shape(ShapeError::EmptyInput),
88 OptimizationError::DimensionMismatch => {
89 NabledError::Shape(ShapeError::DimensionMismatch)
90 }
91 OptimizationError::NonFiniteInput => NabledError::NumericalInstability,
92 OptimizationError::InvalidConfig => {
93 NabledError::InvalidInput("invalid optimizer configuration".to_string())
94 }
95 OptimizationError::MaxIterationsExceeded => NabledError::ConvergenceFailed,
96 }
97 }
98}
99
100impl IntoNabledError for PCAError {
101 fn into_nabled_error(self) -> NabledError {
102 match self {
103 PCAError::EmptyMatrix => NabledError::Shape(ShapeError::EmptyInput),
104 PCAError::InvalidInput(message) => NabledError::InvalidInput(message),
105 PCAError::DecompositionFailed => NabledError::ConvergenceFailed,
106 }
107 }
108}
109
110impl IntoNabledError for RegressionError {
111 fn into_nabled_error(self) -> NabledError {
112 match self {
113 RegressionError::EmptyInput => NabledError::Shape(ShapeError::EmptyInput),
114 RegressionError::DimensionMismatch => NabledError::Shape(ShapeError::DimensionMismatch),
115 RegressionError::Singular => NabledError::SingularMatrix,
116 RegressionError::InvalidInput(message) => NabledError::InvalidInput(message),
117 }
118 }
119}
120
121impl IntoNabledError for StatsError {
122 fn into_nabled_error(self) -> NabledError {
123 match self {
124 StatsError::EmptyMatrix => NabledError::Shape(ShapeError::EmptyInput),
125 StatsError::InsufficientSamples => {
126 NabledError::InvalidInput("at least two observations are required".to_string())
127 }
128 StatsError::NumericalInstability => NabledError::NumericalInstability,
129 }
130 }
131}
132
133#[cfg(test)]
134mod tests {
135 use nabled_core::errors::{IntoNabledError, NabledError, ShapeError};
136
137 use super::*;
138
139 #[test]
140 fn ml_errors_map_to_shared_taxonomy() {
141 assert!(matches!(
142 IterativeError::EmptyMatrix.into_nabled_error(),
143 NabledError::Shape(ShapeError::EmptyInput)
144 ));
145 assert!(matches!(
146 IterativeError::DimensionMismatch.into_nabled_error(),
147 NabledError::Shape(ShapeError::DimensionMismatch)
148 ));
149 assert!(matches!(
150 IterativeError::MaxIterationsExceeded.into_nabled_error(),
151 NabledError::ConvergenceFailed
152 ));
153 assert!(matches!(
154 IterativeError::Breakdown.into_nabled_error(),
155 NabledError::ConvergenceFailed
156 ));
157 assert!(matches!(
158 IterativeError::NotPositiveDefinite.into_nabled_error(),
159 NabledError::NotPositiveDefinite
160 ));
161
162 assert!(matches!(
163 JacobianError::FunctionError("x".to_string()).into_nabled_error(),
164 NabledError::Other(_)
165 ));
166 assert!(matches!(
167 JacobianError::InvalidDimensions("x".to_string()).into_nabled_error(),
168 NabledError::InvalidInput(_)
169 ));
170 assert!(matches!(
171 JacobianError::InvalidStepSize.into_nabled_error(),
172 NabledError::InvalidInput(_)
173 ));
174 assert!(matches!(
175 JacobianError::ConvergenceFailed.into_nabled_error(),
176 NabledError::ConvergenceFailed
177 ));
178 assert!(matches!(
179 JacobianError::EmptyInput.into_nabled_error(),
180 NabledError::Shape(ShapeError::EmptyInput)
181 ));
182 assert!(matches!(
183 JacobianError::DimensionMismatch.into_nabled_error(),
184 NabledError::Shape(ShapeError::DimensionMismatch)
185 ));
186
187 assert!(matches!(
188 OptimizationError::NonFiniteInput.into_nabled_error(),
189 NabledError::NumericalInstability
190 ));
191 assert!(matches!(
192 OptimizationError::InvalidConfig.into_nabled_error(),
193 NabledError::InvalidInput(_)
194 ));
195 assert!(matches!(
196 OptimizationError::MaxIterationsExceeded.into_nabled_error(),
197 NabledError::ConvergenceFailed
198 ));
199
200 assert!(matches!(
201 PCAError::DecompositionFailed.into_nabled_error(),
202 NabledError::ConvergenceFailed
203 ));
204 assert!(matches!(
205 PCAError::InvalidInput("x".to_string()).into_nabled_error(),
206 NabledError::InvalidInput(_)
207 ));
208
209 assert!(matches!(
210 RegressionError::Singular.into_nabled_error(),
211 NabledError::SingularMatrix
212 ));
213
214 assert!(matches!(
215 StatsError::EmptyMatrix.into_nabled_error(),
216 NabledError::Shape(ShapeError::EmptyInput)
217 ));
218 assert!(matches!(
219 StatsError::InsufficientSamples.into_nabled_error(),
220 NabledError::InvalidInput(_)
221 ));
222 assert!(matches!(
223 StatsError::NumericalInstability.into_nabled_error(),
224 NabledError::NumericalInstability
225 ));
226 }
227}