1use serde::{Deserialize, Serialize};
2
3#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
5pub enum RidgeDeterminantMode {
6 Auto,
8 Full,
10 PositivePart,
12}
13
14#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
16pub struct RidgePolicy {
17 pub rho_independent: bool,
19 pub include_quadratic_penalty: bool,
21 pub include_penalty_logdet: bool,
23 pub include_laplacehessian: bool,
25 pub determinant_mode: RidgeDeterminantMode,
27}
28
29impl RidgePolicy {
30 pub const fn explicit_stabilization_full() -> Self {
34 Self {
35 rho_independent: true,
36 include_quadratic_penalty: true,
37 include_penalty_logdet: true,
38 include_laplacehessian: true,
39 determinant_mode: RidgeDeterminantMode::Auto,
40 }
41 }
42
43 pub const fn explicit_stabilization_full_exact() -> Self {
44 Self {
45 rho_independent: true,
46 include_quadratic_penalty: true,
47 include_penalty_logdet: true,
48 include_laplacehessian: true,
49 determinant_mode: RidgeDeterminantMode::Full,
50 }
51 }
52
53 pub const fn explicit_stabilization_pospart() -> Self {
55 Self {
56 rho_independent: true,
57 include_quadratic_penalty: true,
58 include_penalty_logdet: true,
59 include_laplacehessian: true,
60 determinant_mode: RidgeDeterminantMode::PositivePart,
61 }
62 }
63
64 pub const fn solver_only() -> Self {
75 Self {
76 rho_independent: true,
77 include_quadratic_penalty: false,
78 include_penalty_logdet: false,
79 include_laplacehessian: false,
80 determinant_mode: RidgeDeterminantMode::PositivePart,
81 }
82 }
83}
84
85#[cfg(test)]
86mod ridge_policy_tests {
87 use super::*;
88
89 #[test]
90 fn explicit_stabilization_full_includes_all_terms() {
91 let p = RidgePolicy::explicit_stabilization_full();
92 assert!(p.rho_independent);
93 assert!(p.include_quadratic_penalty);
94 assert!(p.include_penalty_logdet);
95 assert!(p.include_laplacehessian);
96 assert_eq!(p.determinant_mode, RidgeDeterminantMode::Auto);
97 }
98
99 #[test]
100 fn explicit_stabilization_full_exact_uses_full_determinant() {
101 let p = RidgePolicy::explicit_stabilization_full_exact();
102 assert!(p.include_penalty_logdet);
103 assert_eq!(p.determinant_mode, RidgeDeterminantMode::Full);
104 }
105
106 #[test]
107 fn explicit_stabilization_pospart_uses_positive_part_determinant() {
108 let p = RidgePolicy::explicit_stabilization_pospart();
109 assert!(p.include_penalty_logdet);
110 assert_eq!(p.determinant_mode, RidgeDeterminantMode::PositivePart);
111 }
112
113 #[test]
114 fn solver_only_ridge_policy_stays_off_objective_accounting() {
115 let p = RidgePolicy::solver_only();
116 assert!(p.rho_independent);
117 assert!(!p.include_quadratic_penalty);
118 assert!(!p.include_penalty_logdet);
119 assert!(!p.include_laplacehessian);
120 }
121
122 #[test]
123 fn determinant_mode_variants_are_distinct() {
124 assert_ne!(RidgeDeterminantMode::Auto, RidgeDeterminantMode::Full);
125 assert_ne!(RidgeDeterminantMode::Full, RidgeDeterminantMode::PositivePart);
126 assert_ne!(RidgeDeterminantMode::Auto, RidgeDeterminantMode::PositivePart);
127 }
128}