1use simba::scalar::ComplexField;
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub enum TworkType {
10 Float64 = 0, Float64X2 = 1, Auto = -1, }
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq)]
22pub enum SVDStrategy {
23 Fast = 0, Accurate = 1, Auto = -1, }
30
31pub fn safe_epsilon(
50 epsilon: f64,
51 twork: TworkType,
52 svd_strategy: SVDStrategy,
53) -> (f64, TworkType, SVDStrategy) {
54 if epsilon < 0.0 {
56 panic!("eps_required must be non-negative");
57 }
58
59 let twork_actual = match twork {
61 TworkType::Auto => {
62 if epsilon.is_nan() || epsilon < 1e-8 {
63 TworkType::Float64X2 } else {
65 TworkType::Float64
66 }
67 }
68 other => other,
69 };
70
71 let safe_eps = match twork_actual {
73 TworkType::Float64 => {
74 1e-8
77 }
78 TworkType::Float64X2 => {
79 use crate::numeric::CustomNumeric;
81 crate::Df64::epsilon().sqrt().to_f64()
82 }
83 _ => 1e-8,
84 };
85
86 let svd_strategy_actual = match svd_strategy {
88 SVDStrategy::Auto => {
89 if !epsilon.is_nan() && epsilon < safe_eps {
90 SVDStrategy::Accurate
92 } else {
93 SVDStrategy::Fast
94 }
95 }
96 other => other,
97 };
98
99 (safe_eps, twork_actual, svd_strategy_actual)
100}
101
102#[cfg(test)]
103mod tests {
104 use super::*;
105
106 #[test]
107 fn test_safe_epsilon_auto_float64() {
108 let (safe_eps, twork, _) = safe_epsilon(1e-7, TworkType::Auto, SVDStrategy::Auto);
109 assert_eq!(twork, TworkType::Float64);
110 assert_eq!(safe_eps, 1e-8);
111 }
112
113 #[test]
114 fn test_safe_epsilon_auto_float64x2() {
115 let (safe_eps, twork, _) = safe_epsilon(1e-10, TworkType::Auto, SVDStrategy::Auto);
116 assert_eq!(twork, TworkType::Float64X2);
117 assert!((safe_eps - 1.5700924586837752e-16).abs() < 1e-20);
119 }
120
121 #[test]
122 fn test_safe_epsilon_explicit_precision() {
123 let (safe_eps, twork, _) = safe_epsilon(1e-7, TworkType::Float64X2, SVDStrategy::Auto);
124 assert_eq!(twork, TworkType::Float64X2);
125 assert!((safe_eps - 1.5700924586837752e-16).abs() < 1e-20);
127 }
128
129 #[test]
130 fn test_svd_strategy_auto_accurate() {
131 let (_, _, strategy) = safe_epsilon(1e-20, TworkType::Auto, SVDStrategy::Auto);
133 assert_eq!(strategy, SVDStrategy::Accurate);
134 }
135
136 #[test]
137 fn test_svd_strategy_auto_fast() {
138 let (_, _, strategy) = safe_epsilon(1e-7, TworkType::Auto, SVDStrategy::Auto);
139 assert_eq!(strategy, SVDStrategy::Fast);
140 }
141
142 #[test]
143 #[should_panic(expected = "eps_required must be non-negative")]
144 fn test_negative_epsilon_panics() {
145 safe_epsilon(-1.0, TworkType::Auto, SVDStrategy::Auto);
146 }
147}