1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
use serde::{Deserialize, Serialize};
/// How ridge-adjusted determinants should be evaluated for outer criteria.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum RidgeDeterminantMode {
/// Use exact full logdet.
Auto,
/// Use full log-determinant of the ridged matrix (requires SPD in practice).
Full,
/// Use positive-part pseudo-determinant (sum log ev for ev > floor).
PositivePart,
}
/// Global policy governing how a stabilization ridge participates in objectives.
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub struct RidgePolicy {
/// Must remain independent of smoothing parameters (`rho`) for smooth outer derivatives.
pub rho_independent: bool,
/// Include ridge in quadratic penalty term: `0.5 * delta * ||beta||^2`.
pub include_quadratic_penalty: bool,
/// Include ridge in penalty determinant term (e.g. `log|S_lambda + delta I|`).
pub include_penalty_logdet: bool,
/// Include ridge in Hessian used by Laplace term / implicit differentiation.
pub include_laplacehessian: bool,
/// Determinant evaluation mode when ridge participates in logdet terms.
pub determinant_mode: RidgeDeterminantMode,
}
impl RidgePolicy {
/// Default policy used by PIRLS/REML path:
/// treat stabilization ridge as an explicit `delta I` prior contribution
/// with adaptive logdet evaluation.
pub const fn explicit_stabilization_full() -> Self {
Self {
rho_independent: true,
include_quadratic_penalty: true,
include_penalty_logdet: true,
include_laplacehessian: true,
determinant_mode: RidgeDeterminantMode::Auto,
}
}
pub const fn explicit_stabilization_full_exact() -> Self {
Self {
rho_independent: true,
include_quadratic_penalty: true,
include_penalty_logdet: true,
include_laplacehessian: true,
determinant_mode: RidgeDeterminantMode::Full,
}
}
/// Variant used when pseudo-determinants are required for indefinite matrices.
pub const fn explicit_stabilization_pospart() -> Self {
Self {
rho_independent: true,
include_quadratic_penalty: true,
include_penalty_logdet: true,
include_laplacehessian: true,
determinant_mode: RidgeDeterminantMode::PositivePart,
}
}
/// Solver-only stabilization: the ridge `δI` stabilizes the inner linear
/// solve (it bounds the Newton step `(H+δI)⁻¹∇`) but is **excluded** from
/// the REML/LAML objective — no `½·δ·‖β‖²` quadratic-penalty term, no
/// `δ`-shift of the penalty log-determinant, no `δ`-shift of the Laplace
/// Hessian. Use this when a numerical floor is needed purely to keep the
/// linear algebra finite during screening and must NOT bias the
/// smoothing-parameter selection or shrink identified coefficients off the
/// MLE. With every `include_*` false the optimized objective equals the
/// true penalized REML criterion, so the value surface and its analytic
/// gradient describe the same objective (gam#747/#748).
pub const fn solver_only() -> Self {
Self {
rho_independent: true,
include_quadratic_penalty: false,
include_penalty_logdet: false,
include_laplacehessian: false,
determinant_mode: RidgeDeterminantMode::PositivePart,
}
}
}
#[cfg(test)]
mod ridge_policy_tests {
use super::*;
#[test]
fn explicit_stabilization_full_includes_all_terms() {
let p = RidgePolicy::explicit_stabilization_full();
assert!(p.rho_independent);
assert!(p.include_quadratic_penalty);
assert!(p.include_penalty_logdet);
assert!(p.include_laplacehessian);
assert_eq!(p.determinant_mode, RidgeDeterminantMode::Auto);
}
#[test]
fn explicit_stabilization_full_exact_uses_full_determinant() {
let p = RidgePolicy::explicit_stabilization_full_exact();
assert!(p.include_penalty_logdet);
assert_eq!(p.determinant_mode, RidgeDeterminantMode::Full);
}
#[test]
fn explicit_stabilization_pospart_uses_positive_part_determinant() {
let p = RidgePolicy::explicit_stabilization_pospart();
assert!(p.include_penalty_logdet);
assert_eq!(p.determinant_mode, RidgeDeterminantMode::PositivePart);
}
#[test]
fn solver_only_ridge_policy_stays_off_objective_accounting() {
let p = RidgePolicy::solver_only();
assert!(p.rho_independent);
assert!(!p.include_quadratic_penalty);
assert!(!p.include_penalty_logdet);
assert!(!p.include_laplacehessian);
}
#[test]
fn determinant_mode_variants_are_distinct() {
assert_ne!(RidgeDeterminantMode::Auto, RidgeDeterminantMode::Full);
assert_ne!(RidgeDeterminantMode::Full, RidgeDeterminantMode::PositivePart);
assert_ne!(RidgeDeterminantMode::Auto, RidgeDeterminantMode::PositivePart);
}
}