Skip to main content

matten_mlprep/
error.rs

1//! Error type for `matten-mlprep` (RFC-024 §7, RFC-028 §5).
2//!
3//! The crate defines its own error type rather than growing core
4//! [`matten::MattenError`] (RFC-022 §8). Every entry point returns `Result`; a
5//! dynamic tensor returns [`MattenMlprepError::DynamicTensor`] rather than
6//! panicking.
7
8use std::fmt;
9
10/// Errors produced by `matten-mlprep` preprocessing functions.
11///
12/// `#[non_exhaustive]` so future variants are not a breaking change.
13#[derive(Debug)]
14#[non_exhaustive]
15pub enum MattenMlprepError {
16    /// A dynamic (`Element`) tensor was passed. Convert it to a numeric tensor
17    /// first with `Tensor::try_numeric()`.
18    DynamicTensor,
19    /// The input was not rank-2. `matten-mlprep` operates only on matrices with
20    /// the convention `rows = samples`, `columns = features`.
21    ExpectedMatrix {
22        /// The shape that was provided.
23        shape: Vec<usize>,
24    },
25    /// `train_ratio` was not a finite value in the open interval `(0.0, 1.0)`.
26    InvalidRatio(f64),
27    /// The requested split would leave the train set empty
28    /// (`floor(rows * train_ratio) == 0`).
29    EmptySplit {
30        /// Number of rows (samples) in the input.
31        rows: usize,
32        /// The requested train ratio.
33        train_ratio: f64,
34    },
35    /// A column has zero variance / range and therefore cannot be scaled.
36    ZeroVariance {
37        /// The index of the offending column (feature).
38        column: usize,
39    },
40    /// Core `matten` rejected a constructed result.
41    Matten(matten::MattenError),
42}
43
44impl fmt::Display for MattenMlprepError {
45    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
46        match self {
47            MattenMlprepError::DynamicTensor => write!(
48                f,
49                "matten-mlprep error: dynamic tensors are not supported; call \
50                 try_numeric() to convert to a numeric tensor first"
51            ),
52            MattenMlprepError::ExpectedMatrix { shape } => write!(
53                f,
54                "matten-mlprep error: expected a rank-2 tensor (rows = samples, \
55                 columns = features), got shape {shape:?}"
56            ),
57            MattenMlprepError::InvalidRatio(r) => write!(
58                f,
59                "matten-mlprep error: train_ratio must be a finite value in (0.0, 1.0), got {r}"
60            ),
61            MattenMlprepError::EmptySplit { rows, train_ratio } => write!(
62                f,
63                "matten-mlprep error: a split of {rows} row(s) at ratio {train_ratio} \
64                 leaves the train set empty; use a larger ratio or more rows"
65            ),
66            MattenMlprepError::ZeroVariance { column } => write!(
67                f,
68                "matten-mlprep error: column {column} has zero variance/range and \
69                 cannot be scaled; drop or handle the constant column first"
70            ),
71            MattenMlprepError::Matten(e) => {
72                write!(f, "matten-mlprep error: matten rejected the result: {e}")
73            }
74        }
75    }
76}
77
78impl std::error::Error for MattenMlprepError {
79    fn source(&self) -> Option<&(dyn std::error::Error + 'static)> {
80        match self {
81            MattenMlprepError::Matten(e) => Some(e),
82            _ => None,
83        }
84    }
85}