Skip to main content

gam_terms/smooth/
error.rs

1//! Typed errors emitted by smooth-term helpers.
2//!
3//! Carved out of the `smooth` module along its first real seam: this is the
4//! error vocabulary every smooth-term builder shares, with no dependency on the
5//! basis/penalty/optimizer machinery that surrounds it. `Display` reproduces the
6//! exact pre-refactor `format!(...)` text byte-for-byte, so string-matching
7//! callers (tests, log assertions) keep working unchanged. Public boundaries
8//! that interface with `term_builder.rs` / `construction` continue to return
9//! `Result<_, String>`; typed `Err(...)` values flow through
10//! `From<SmoothError> for String` at those boundaries via `.into()`.
11
12use gam_problem::BlockCountMismatch;
13
14/// Typed errors emitted by smooth-term helpers in the `smooth` module.
15#[derive(Clone, Debug)]
16pub enum SmoothError {
17    /// Spec-level configuration error: unfrozen knots/centers, invalid
18    /// numeric bounds on coefficient priors, length-scale optimizer options
19    /// that violate `min > 0 < max` / `min < max` invariants, etc.
20    InvalidConfig { reason: String },
21    /// Shape / length disagreement between design columns, penalty blocks,
22    /// coefficient ranges, directional-derivative vectors, theta length, and
23    /// other bookkeeping invariants that are checked at runtime.
24    DimensionMismatch { reason: String },
25    /// Out-of-range index into adaptive hyperparameter components, psi
26    /// derivative blocks, or non-zero block indices for single-block
27    /// custom-family impls that only support `block_idx == 0`.
28    InvalidIndex { reason: String },
29}
30
31gam_linalg::impl_reason_error_boilerplate! {
32    SmoothError {
33        InvalidConfig,
34        DimensionMismatch,
35        InvalidIndex,
36    }
37}
38
39impl From<BlockCountMismatch> for SmoothError {
40    fn from(err: BlockCountMismatch) -> SmoothError {
41        SmoothError::invalid_index(err.message())
42    }
43}
44
45impl SmoothError {
46    #[inline]
47    pub fn invalid_config(reason: impl Into<String>) -> Self {
48        SmoothError::InvalidConfig {
49            reason: reason.into(),
50        }
51    }
52    #[inline]
53    pub fn dimension_mismatch(reason: impl Into<String>) -> Self {
54        SmoothError::DimensionMismatch {
55            reason: reason.into(),
56        }
57    }
58    #[inline]
59    pub fn invalid_index(reason: impl Into<String>) -> Self {
60        SmoothError::InvalidIndex {
61            reason: reason.into(),
62        }
63    }
64}