Skip to main content

model_selection_rs/
error.rs

1//! Error type shared across every splitter and evaluation utility.
2
3use thiserror::Error;
4
5/// Errors returned by splitters and evaluation utilities.
6///
7/// The library follows a deliberate policy on degenerate inputs (mirroring the
8/// convention used across the sibling `imbalance-rs` crate):
9///
10/// * **Warn and adjust** where a sane fallback exists — e.g. a
11///   [`StratifiedKFold`](crate::splitters::StratifiedKFold) class smaller than
12///   `n_splits` is distributed across as many folds as it can fill, with a
13///   warning on stderr, rather than aborting the whole split.
14/// * **Hard-error** where there is no meaningful fallback — e.g. a
15///   [`TimeSeriesSplit`](crate::splitters::TimeSeriesSplit) asked for more
16///   splits than the data can supply a valid train/test window for.
17#[derive(Debug, Error, Clone, PartialEq, Eq)]
18pub enum ModelSelectionError {
19    /// Fewer samples than are needed to form the requested splits.
20    #[error("not enough samples: need at least {needed}, got {got}")]
21    NotEnoughSamples {
22        /// Minimum number of samples the configuration requires.
23        needed: usize,
24        /// Number of samples actually supplied.
25        got: usize,
26    },
27
28    /// A class label had no samples where at least one was required.
29    #[error("class has no samples but was required to be non-empty")]
30    EmptyClass,
31
32    /// A group had no samples where at least one was required.
33    #[error("group has no samples but was required to be non-empty")]
34    EmptyGroup,
35
36    /// The requested number of splits is invalid (must be `>= 2`, and no larger
37    /// than the number of samples / groups the splitter partitions over).
38    #[error("invalid split count: {msg}")]
39    InvalidSplitCount {
40        /// Human-readable explanation of why the count is invalid.
41        msg: String,
42    },
43
44    /// [`TimeSeriesSplit`](crate::splitters::TimeSeriesSplit) could not carve
45    /// out a training window large enough for every requested split.
46    #[error("insufficient training window: {msg}")]
47    InsufficientTrainWindow {
48        /// Human-readable explanation of the shortfall.
49        msg: String,
50    },
51
52    /// Two inputs that had to agree on length did not (e.g. a stored label
53    /// array whose length differs from `n_samples` passed to `split`).
54    #[error("shape mismatch: expected length {expected}, got {got}")]
55    ShapeMismatch {
56        /// Length that was expected.
57        expected: usize,
58        /// Length that was supplied.
59        got: usize,
60    },
61}
62
63/// Convenience alias for results returned throughout this crate.
64pub type Result<T> = std::result::Result<T, ModelSelectionError>;