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