1use nabled_core::errors::{IntoNabledError, NabledError, ShapeError};
40
41use crate::accelerator::backends::AcceleratorError;
42use crate::cholesky::CholeskyError;
43use crate::eigen::EigenError;
44use crate::lu::LUError;
45use crate::matrix::MatrixError;
46use crate::matrix_functions::MatrixFunctionError;
47use crate::orthogonalization::OrthogonalizationError;
48use crate::polar::PolarError;
49use crate::qr::QRError;
50use crate::schur::SchurError;
51use crate::sparse::SparseError;
52use crate::svd::SVDError;
53use crate::sylvester::SylvesterError;
54use crate::tensor::TensorError;
55use crate::triangular::TriangularError;
56use crate::vector::VectorError;
57
58pub mod accelerator;
59pub mod batched;
60mod internal;
61#[cfg(all(test, feature = "magma-system"))]
62mod magma_verification;
63mod provider;
64
65pub mod cholesky;
66pub mod eigen;
67pub mod lu;
68pub mod matrix;
69pub mod matrix_functions;
70pub mod orthogonalization;
71pub mod polar;
72pub mod qr;
73pub mod schur;
74pub mod sparse;
75pub mod svd;
76pub mod sylvester;
77pub mod tensor;
78pub mod triangular;
79pub mod vector;
80
81impl IntoNabledError for AcceleratorError {
82 fn into_nabled_error(self) -> NabledError {
83 match self {
84 AcceleratorError::UnsupportedBackend(kind) => {
85 NabledError::Other(format!("backend {kind:?} is not currently available"))
86 }
87 AcceleratorError::InvalidChunkSize => {
88 NabledError::InvalidInput("chunk size must be greater than zero".to_string())
89 }
90 AcceleratorError::DimensionMismatch => {
91 NabledError::Shape(ShapeError::DimensionMismatch)
92 }
93 AcceleratorError::FeatureNotEnabled => {
94 NabledError::Other("requested accelerator feature is not enabled".to_string())
95 }
96 AcceleratorError::DeviceUnavailable => {
97 NabledError::Other("no suitable GPU device is available".to_string())
98 }
99 AcceleratorError::KernelExecutionFailed => {
100 NabledError::Other("GPU kernel execution failed".to_string())
101 }
102 }
103 }
104}
105
106impl IntoNabledError for CholeskyError {
107 fn into_nabled_error(self) -> NabledError {
108 match self {
109 CholeskyError::EmptyMatrix => NabledError::Shape(ShapeError::EmptyInput),
110 CholeskyError::NotSquare => NabledError::Shape(ShapeError::NotSquare),
111 CholeskyError::NotPositiveDefinite => NabledError::NotPositiveDefinite,
112 CholeskyError::InvalidInput(message) => NabledError::InvalidInput(message),
113 CholeskyError::NumericalInstability => NabledError::NumericalInstability,
114 }
115 }
116}
117
118impl IntoNabledError for EigenError {
119 fn into_nabled_error(self) -> NabledError {
120 match self {
121 EigenError::EmptyMatrix => NabledError::Shape(ShapeError::EmptyInput),
122 EigenError::NotSquare => NabledError::Shape(ShapeError::NotSquare),
123 EigenError::NotSymmetric => NabledError::NotSymmetric,
124 EigenError::InvalidDimensions => NabledError::Shape(ShapeError::DimensionMismatch),
125 EigenError::NotPositiveDefinite => NabledError::NotPositiveDefinite,
126 EigenError::ConvergenceFailed => NabledError::ConvergenceFailed,
127 EigenError::NumericalInstability => NabledError::NumericalInstability,
128 }
129 }
130}
131
132impl IntoNabledError for LUError {
133 fn into_nabled_error(self) -> NabledError {
134 match self {
135 LUError::EmptyMatrix => NabledError::Shape(ShapeError::EmptyInput),
136 LUError::NotSquare => NabledError::Shape(ShapeError::NotSquare),
137 LUError::SingularMatrix => NabledError::SingularMatrix,
138 LUError::ConvergenceFailed => NabledError::ConvergenceFailed,
139 LUError::InvalidInput(message) => NabledError::InvalidInput(message),
140 LUError::NumericalInstability => NabledError::NumericalInstability,
141 }
142 }
143}
144
145impl IntoNabledError for MatrixError {
146 fn into_nabled_error(self) -> NabledError {
147 match self {
148 MatrixError::EmptyInput => NabledError::Shape(ShapeError::EmptyInput),
149 MatrixError::DimensionMismatch => NabledError::Shape(ShapeError::DimensionMismatch),
150 }
151 }
152}
153
154impl IntoNabledError for MatrixFunctionError {
155 fn into_nabled_error(self) -> NabledError {
156 match self {
157 MatrixFunctionError::EmptyMatrix => NabledError::Shape(ShapeError::EmptyInput),
158 MatrixFunctionError::NotSquare => NabledError::Shape(ShapeError::NotSquare),
159 MatrixFunctionError::NotSymmetric => NabledError::NotSymmetric,
160 MatrixFunctionError::NotPositiveDefinite => NabledError::NotPositiveDefinite,
161 MatrixFunctionError::ConvergenceFailed => NabledError::ConvergenceFailed,
162 MatrixFunctionError::InvalidInput(message) => NabledError::InvalidInput(message),
163 }
164 }
165}
166
167impl IntoNabledError for OrthogonalizationError {
168 fn into_nabled_error(self) -> NabledError {
169 match self {
170 OrthogonalizationError::EmptyMatrix => NabledError::Shape(ShapeError::EmptyInput),
171 OrthogonalizationError::NumericalInstability => NabledError::NumericalInstability,
172 }
173 }
174}
175
176impl IntoNabledError for PolarError {
177 fn into_nabled_error(self) -> NabledError {
178 match self {
179 PolarError::EmptyMatrix => NabledError::Shape(ShapeError::EmptyInput),
180 PolarError::NotSquare => NabledError::Shape(ShapeError::NotSquare),
181 PolarError::DecompositionFailed => NabledError::ConvergenceFailed,
182 PolarError::NumericalInstability => NabledError::NumericalInstability,
183 }
184 }
185}
186
187impl IntoNabledError for QRError {
188 fn into_nabled_error(self) -> NabledError {
189 match self {
190 QRError::EmptyMatrix => NabledError::Shape(ShapeError::EmptyInput),
191 QRError::SingularMatrix => NabledError::SingularMatrix,
192 QRError::ConvergenceFailed => NabledError::ConvergenceFailed,
193 QRError::InvalidDimensions(message) | QRError::InvalidInput(message) => {
194 NabledError::InvalidInput(message)
195 }
196 QRError::NumericalInstability => NabledError::NumericalInstability,
197 }
198 }
199}
200
201impl IntoNabledError for SchurError {
202 fn into_nabled_error(self) -> NabledError {
203 match self {
204 SchurError::EmptyMatrix => NabledError::Shape(ShapeError::EmptyInput),
205 SchurError::NotSquare => NabledError::Shape(ShapeError::NotSquare),
206 SchurError::ConvergenceFailed => NabledError::ConvergenceFailed,
207 SchurError::NumericalInstability => NabledError::NumericalInstability,
208 SchurError::InvalidInput(message) => NabledError::InvalidInput(message),
209 }
210 }
211}
212
213impl IntoNabledError for SparseError {
214 fn into_nabled_error(self) -> NabledError {
215 match self {
216 SparseError::EmptyInput => NabledError::Shape(ShapeError::EmptyInput),
217 SparseError::InvalidStructure => {
218 NabledError::InvalidInput("invalid sparse structure".to_string())
219 }
220 SparseError::DimensionMismatch => NabledError::Shape(ShapeError::DimensionMismatch),
221 SparseError::SingularMatrix => NabledError::SingularMatrix,
222 SparseError::MaxIterationsExceeded => NabledError::ConvergenceFailed,
223 }
224 }
225}
226
227impl IntoNabledError for SVDError {
228 fn into_nabled_error(self) -> NabledError {
229 match self {
230 SVDError::EmptyMatrix => NabledError::Shape(ShapeError::EmptyInput),
231 SVDError::NotSquare => NabledError::Shape(ShapeError::NotSquare),
232 SVDError::ConvergenceFailed => NabledError::ConvergenceFailed,
233 SVDError::InvalidInput(message) => NabledError::InvalidInput(message),
234 }
235 }
236}
237
238impl IntoNabledError for SylvesterError {
239 fn into_nabled_error(self) -> NabledError {
240 match self {
241 SylvesterError::EmptyMatrix => NabledError::Shape(ShapeError::EmptyInput),
242 SylvesterError::NotSquare => NabledError::Shape(ShapeError::NotSquare),
243 SylvesterError::DimensionMismatch => NabledError::Shape(ShapeError::DimensionMismatch),
244 SylvesterError::SingularSystem => NabledError::SingularMatrix,
245 SylvesterError::InvalidInput(message) => NabledError::InvalidInput(message),
246 }
247 }
248}
249
250impl IntoNabledError for TriangularError {
251 fn into_nabled_error(self) -> NabledError {
252 match self {
253 TriangularError::Shape(error) => NabledError::Shape(error),
254 TriangularError::Singular => NabledError::SingularMatrix,
255 }
256 }
257}
258
259impl IntoNabledError for TensorError {
260 fn into_nabled_error(self) -> NabledError {
261 match self {
262 TensorError::EmptyInput => NabledError::Shape(ShapeError::EmptyInput),
263 TensorError::DimensionMismatch => NabledError::Shape(ShapeError::DimensionMismatch),
264 }
265 }
266}
267
268impl IntoNabledError for VectorError {
269 fn into_nabled_error(self) -> NabledError {
270 match self {
271 VectorError::EmptyInput => NabledError::Shape(ShapeError::EmptyInput),
272 VectorError::DimensionMismatch => NabledError::Shape(ShapeError::DimensionMismatch),
273 VectorError::ZeroNorm => NabledError::InvalidInput(
274 "cosine similarity is undefined for zero-norm vectors".to_string(),
275 ),
276 }
277 }
278}
279
280#[cfg(test)]
281mod tests {
282 use nabled_core::errors::{IntoNabledError, NabledError, ShapeError};
283
284 use super::*;
285 use crate::accelerator::backends::BackendKind;
286
287 #[test]
288 fn linalg_errors_map_to_shared_taxonomy() {
289 assert!(matches!(
290 CholeskyError::EmptyMatrix.into_nabled_error(),
291 NabledError::Shape(ShapeError::EmptyInput)
292 ));
293 assert!(matches!(
294 CholeskyError::NotSquare.into_nabled_error(),
295 NabledError::Shape(ShapeError::NotSquare)
296 ));
297 assert!(matches!(
298 CholeskyError::NotPositiveDefinite.into_nabled_error(),
299 NabledError::NotPositiveDefinite
300 ));
301 assert!(matches!(
302 CholeskyError::NumericalInstability.into_nabled_error(),
303 NabledError::NumericalInstability
304 ));
305 assert!(matches!(
306 CholeskyError::InvalidInput("x".to_string()).into_nabled_error(),
307 NabledError::InvalidInput(_)
308 ));
309
310 assert!(matches!(EigenError::NotSymmetric.into_nabled_error(), NabledError::NotSymmetric));
311 assert!(matches!(
312 EigenError::InvalidDimensions.into_nabled_error(),
313 NabledError::Shape(ShapeError::DimensionMismatch)
314 ));
315
316 assert!(matches!(LUError::SingularMatrix.into_nabled_error(), NabledError::SingularMatrix));
317 assert!(matches!(
318 MatrixError::EmptyInput.into_nabled_error(),
319 NabledError::Shape(ShapeError::EmptyInput)
320 ));
321 assert!(matches!(
322 MatrixError::DimensionMismatch.into_nabled_error(),
323 NabledError::Shape(ShapeError::DimensionMismatch)
324 ));
325
326 assert!(matches!(
327 MatrixFunctionError::ConvergenceFailed.into_nabled_error(),
328 NabledError::ConvergenceFailed
329 ));
330
331 assert!(matches!(
332 OrthogonalizationError::NumericalInstability.into_nabled_error(),
333 NabledError::NumericalInstability
334 ));
335
336 assert!(matches!(
337 PolarError::DecompositionFailed.into_nabled_error(),
338 NabledError::ConvergenceFailed
339 ));
340
341 assert!(matches!(QRError::SingularMatrix.into_nabled_error(), NabledError::SingularMatrix));
342 assert!(matches!(
343 QRError::InvalidDimensions("x".to_string()).into_nabled_error(),
344 NabledError::InvalidInput(_)
345 ));
346 assert!(matches!(
347 QRError::InvalidInput("y".to_string()).into_nabled_error(),
348 NabledError::InvalidInput(_)
349 ));
350 }
351
352 #[test]
353 fn linalg_errors_map_to_shared_taxonomy_additional_domains() {
354 assert!(matches!(
355 SchurError::InvalidInput("x".to_string()).into_nabled_error(),
356 NabledError::InvalidInput(_)
357 ));
358
359 assert!(matches!(
360 SparseError::InvalidStructure.into_nabled_error(),
361 NabledError::InvalidInput(_)
362 ));
363 assert!(matches!(
364 SparseError::DimensionMismatch.into_nabled_error(),
365 NabledError::Shape(ShapeError::DimensionMismatch)
366 ));
367 assert!(matches!(
368 SparseError::SingularMatrix.into_nabled_error(),
369 NabledError::SingularMatrix
370 ));
371 assert!(matches!(
372 SparseError::MaxIterationsExceeded.into_nabled_error(),
373 NabledError::ConvergenceFailed
374 ));
375
376 assert!(matches!(
377 SVDError::ConvergenceFailed.into_nabled_error(),
378 NabledError::ConvergenceFailed
379 ));
380
381 assert!(matches!(
382 SylvesterError::SingularSystem.into_nabled_error(),
383 NabledError::SingularMatrix
384 ));
385
386 assert!(matches!(
387 TriangularError::Singular.into_nabled_error(),
388 NabledError::SingularMatrix
389 ));
390
391 assert!(matches!(VectorError::ZeroNorm.into_nabled_error(), NabledError::InvalidInput(_)));
392 assert!(matches!(
393 TensorError::EmptyInput.into_nabled_error(),
394 NabledError::Shape(ShapeError::EmptyInput)
395 ));
396 assert!(matches!(
397 TensorError::DimensionMismatch.into_nabled_error(),
398 NabledError::Shape(ShapeError::DimensionMismatch)
399 ));
400 assert!(matches!(
401 AcceleratorError::UnsupportedBackend(BackendKind::Gpu).into_nabled_error(),
402 NabledError::Other(_)
403 ));
404 assert!(matches!(
405 AcceleratorError::InvalidChunkSize.into_nabled_error(),
406 NabledError::InvalidInput(_)
407 ));
408 assert!(matches!(
409 AcceleratorError::DimensionMismatch.into_nabled_error(),
410 NabledError::Shape(ShapeError::DimensionMismatch)
411 ));
412 assert!(matches!(
413 AcceleratorError::FeatureNotEnabled.into_nabled_error(),
414 NabledError::Other(_)
415 ));
416 }
417
418 #[test]
419 fn linalg_error_mapping_covers_remaining_variants_part_1() {
420 assert!(matches!(
421 EigenError::EmptyMatrix.into_nabled_error(),
422 NabledError::Shape(ShapeError::EmptyInput)
423 ));
424 assert!(matches!(
425 EigenError::NotSquare.into_nabled_error(),
426 NabledError::Shape(ShapeError::NotSquare)
427 ));
428 assert!(matches!(
429 EigenError::NotPositiveDefinite.into_nabled_error(),
430 NabledError::NotPositiveDefinite
431 ));
432 assert!(matches!(
433 EigenError::ConvergenceFailed.into_nabled_error(),
434 NabledError::ConvergenceFailed
435 ));
436 assert!(matches!(
437 EigenError::NumericalInstability.into_nabled_error(),
438 NabledError::NumericalInstability
439 ));
440
441 assert!(matches!(
442 LUError::EmptyMatrix.into_nabled_error(),
443 NabledError::Shape(ShapeError::EmptyInput)
444 ));
445 assert!(matches!(
446 LUError::NotSquare.into_nabled_error(),
447 NabledError::Shape(ShapeError::NotSquare)
448 ));
449 assert!(matches!(
450 LUError::InvalidInput("x".to_string()).into_nabled_error(),
451 NabledError::InvalidInput(_)
452 ));
453 assert!(matches!(
454 LUError::ConvergenceFailed.into_nabled_error(),
455 NabledError::ConvergenceFailed
456 ));
457 assert!(matches!(
458 LUError::NumericalInstability.into_nabled_error(),
459 NabledError::NumericalInstability
460 ));
461
462 assert!(matches!(
463 QRError::EmptyMatrix.into_nabled_error(),
464 NabledError::Shape(ShapeError::EmptyInput)
465 ));
466 assert!(matches!(
467 QRError::ConvergenceFailed.into_nabled_error(),
468 NabledError::ConvergenceFailed
469 ));
470 assert!(matches!(
471 QRError::NumericalInstability.into_nabled_error(),
472 NabledError::NumericalInstability
473 ));
474 }
475
476 #[test]
477 fn linalg_error_mapping_covers_remaining_variants_part_2() {
478 assert!(matches!(
479 MatrixFunctionError::EmptyMatrix.into_nabled_error(),
480 NabledError::Shape(ShapeError::EmptyInput)
481 ));
482 assert!(matches!(
483 MatrixFunctionError::NotSquare.into_nabled_error(),
484 NabledError::Shape(ShapeError::NotSquare)
485 ));
486 assert!(matches!(
487 MatrixFunctionError::NotSymmetric.into_nabled_error(),
488 NabledError::NotSymmetric
489 ));
490 assert!(matches!(
491 MatrixFunctionError::NotPositiveDefinite.into_nabled_error(),
492 NabledError::NotPositiveDefinite
493 ));
494 assert!(matches!(
495 MatrixFunctionError::InvalidInput("x".to_string()).into_nabled_error(),
496 NabledError::InvalidInput(_)
497 ));
498
499 assert!(matches!(
500 OrthogonalizationError::EmptyMatrix.into_nabled_error(),
501 NabledError::Shape(ShapeError::EmptyInput)
502 ));
503
504 assert!(matches!(
505 PolarError::EmptyMatrix.into_nabled_error(),
506 NabledError::Shape(ShapeError::EmptyInput)
507 ));
508 assert!(matches!(
509 PolarError::NotSquare.into_nabled_error(),
510 NabledError::Shape(ShapeError::NotSquare)
511 ));
512 assert!(matches!(
513 PolarError::NumericalInstability.into_nabled_error(),
514 NabledError::NumericalInstability
515 ));
516
517 assert!(matches!(
518 SchurError::EmptyMatrix.into_nabled_error(),
519 NabledError::Shape(ShapeError::EmptyInput)
520 ));
521 assert!(matches!(
522 SchurError::NotSquare.into_nabled_error(),
523 NabledError::Shape(ShapeError::NotSquare)
524 ));
525 assert!(matches!(
526 SchurError::ConvergenceFailed.into_nabled_error(),
527 NabledError::ConvergenceFailed
528 ));
529 assert!(matches!(
530 SchurError::NumericalInstability.into_nabled_error(),
531 NabledError::NumericalInstability
532 ));
533
534 assert!(matches!(
535 SparseError::EmptyInput.into_nabled_error(),
536 NabledError::Shape(ShapeError::EmptyInput)
537 ));
538 }
539
540 #[test]
541 fn linalg_error_mapping_covers_remaining_variants_part_3() {
542 assert!(matches!(
543 SVDError::EmptyMatrix.into_nabled_error(),
544 NabledError::Shape(ShapeError::EmptyInput)
545 ));
546 assert!(matches!(
547 SVDError::NotSquare.into_nabled_error(),
548 NabledError::Shape(ShapeError::NotSquare)
549 ));
550 assert!(matches!(
551 SVDError::InvalidInput("x".to_string()).into_nabled_error(),
552 NabledError::InvalidInput(_)
553 ));
554
555 assert!(matches!(
556 SylvesterError::EmptyMatrix.into_nabled_error(),
557 NabledError::Shape(ShapeError::EmptyInput)
558 ));
559 assert!(matches!(
560 SylvesterError::NotSquare.into_nabled_error(),
561 NabledError::Shape(ShapeError::NotSquare)
562 ));
563 assert!(matches!(
564 SylvesterError::DimensionMismatch.into_nabled_error(),
565 NabledError::Shape(ShapeError::DimensionMismatch)
566 ));
567 assert!(matches!(
568 SylvesterError::InvalidInput("x".to_string()).into_nabled_error(),
569 NabledError::InvalidInput(_)
570 ));
571
572 assert!(matches!(
573 TriangularError::Shape(ShapeError::NotSquare).into_nabled_error(),
574 NabledError::Shape(ShapeError::NotSquare)
575 ));
576
577 assert!(matches!(
578 VectorError::EmptyInput.into_nabled_error(),
579 NabledError::Shape(ShapeError::EmptyInput)
580 ));
581 assert!(matches!(
582 VectorError::DimensionMismatch.into_nabled_error(),
583 NabledError::Shape(ShapeError::DimensionMismatch)
584 ));
585 }
586}