Skip to main content

gam_problem/
family_options.rs

1//! Fit-time outer-objective and exact-derivative-order declarations shared by
2//! the custom-family solver entry points.
3//!
4//! These are the neutral, dependency-free capability enums lifted out of
5//! `src/families/custom_family/options.rs` so they live below `solver` in the
6//! crate graph. The cost/assert helpers and `BlockwiseFitOptions` /
7//! `OuterDerivativePolicy` remain in the root crate because they depend on
8//! root-crate types (`OuterScoreSubsample`, `JointPenaltyBundle`,
9//! `OuterEvalContext`, `crate::solver::rho_optimizer::OuterEvalOrder`,
10//! `gam_runtime::warm_start::Session`) and on the parameter-block-spec types
11//! still being relocated into this crate.
12
13#[derive(Debug, Clone, Copy, PartialEq, Eq)]
14pub enum ExactNewtonOuterObjective {
15    RidgedQuadraticReml,
16    StrictPseudoLaplace,
17}
18
19/// Highest exact outer derivative order a family wants to expose at the
20/// current realized problem scale.
21#[derive(Clone, Copy, Debug, PartialEq, Eq, PartialOrd, Ord)]
22pub enum ExactOuterDerivativeOrder {
23    Zeroth,
24    First,
25    Second,
26}
27
28impl ExactOuterDerivativeOrder {
29    pub const fn has_gradient(self) -> bool {
30        !matches!(self, Self::Zeroth)
31    }
32
33    pub const fn has_hessian(self) -> bool {
34        matches!(self, Self::Second)
35    }
36}
37
38#[cfg(test)]
39mod tests {
40    use super::*;
41
42    #[test]
43    fn zeroth_order_has_no_gradient_or_hessian() {
44        let o = ExactOuterDerivativeOrder::Zeroth;
45        assert!(!o.has_gradient());
46        assert!(!o.has_hessian());
47    }
48
49    #[test]
50    fn first_order_has_gradient_but_not_hessian() {
51        let o = ExactOuterDerivativeOrder::First;
52        assert!(o.has_gradient());
53        assert!(!o.has_hessian());
54    }
55
56    #[test]
57    fn second_order_has_both_gradient_and_hessian() {
58        let o = ExactOuterDerivativeOrder::Second;
59        assert!(o.has_gradient());
60        assert!(o.has_hessian());
61    }
62
63    #[test]
64    fn ordering_is_zeroth_lt_first_lt_second() {
65        use ExactOuterDerivativeOrder::*;
66        assert!(Zeroth < First);
67        assert!(First < Second);
68        assert!(Zeroth < Second);
69    }
70}