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}