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