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>;