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