1pub const NUMERICAL_EPS: f64 = 1e-10;
5
6pub const DEFAULT_CONVERGENCE_TOL: f64 = 1e-6;
8
9pub fn extract_curves(data: &[f64], n: usize, m: usize) -> Vec<Vec<f64>> {
22 (0..n)
23 .map(|i| (0..m).map(|j| data[i + j * n]).collect())
24 .collect()
25}
26
27pub fn l2_distance(curve1: &[f64], curve2: &[f64], weights: &[f64]) -> f64 {
37 let mut dist_sq = 0.0;
38 for i in 0..curve1.len() {
39 let diff = curve1[i] - curve2[i];
40 dist_sq += diff * diff * weights[i];
41 }
42 dist_sq.sqrt()
43}
44
45pub fn simpsons_weights(argvals: &[f64]) -> Vec<f64> {
55 let n = argvals.len();
56 if n < 2 {
57 return vec![1.0; n];
58 }
59
60 let mut weights = vec![0.0; n];
61
62 if n == 2 {
63 let h = argvals[1] - argvals[0];
65 weights[0] = h / 2.0;
66 weights[1] = h / 2.0;
67 return weights;
68 }
69
70 for i in 0..n {
72 if i == 0 {
73 weights[i] = (argvals[1] - argvals[0]) / 2.0;
74 } else if i == n - 1 {
75 weights[i] = (argvals[n - 1] - argvals[n - 2]) / 2.0;
76 } else {
77 weights[i] = (argvals[i + 1] - argvals[i - 1]) / 2.0;
78 }
79 }
80
81 weights
82}
83
84pub fn simpsons_weights_2d(argvals_s: &[f64], argvals_t: &[f64]) -> Vec<f64> {
95 let weights_s = simpsons_weights(argvals_s);
96 let weights_t = simpsons_weights(argvals_t);
97 let m1 = argvals_s.len();
98 let m2 = argvals_t.len();
99
100 let mut weights = vec![0.0; m1 * m2];
101 for i in 0..m1 {
102 for j in 0..m2 {
103 weights[i * m2 + j] = weights_s[i] * weights_t[j];
104 }
105 }
106 weights
107}
108
109#[cfg(test)]
110mod tests {
111 use super::*;
112
113 #[test]
114 fn test_simpsons_weights_uniform() {
115 let argvals = vec![0.0, 0.25, 0.5, 0.75, 1.0];
116 let weights = simpsons_weights(&argvals);
117 let sum: f64 = weights.iter().sum();
118 assert!((sum - 1.0).abs() < NUMERICAL_EPS);
119 }
120
121 #[test]
122 fn test_simpsons_weights_2d() {
123 let argvals_s = vec![0.0, 0.5, 1.0];
124 let argvals_t = vec![0.0, 0.5, 1.0];
125 let weights = simpsons_weights_2d(&argvals_s, &argvals_t);
126 let sum: f64 = weights.iter().sum();
127 assert!((sum - 1.0).abs() < NUMERICAL_EPS);
128 }
129
130 #[test]
131 fn test_extract_curves() {
132 let data = vec![1.0, 4.0, 2.0, 5.0, 3.0, 6.0];
135 let curves = extract_curves(&data, 2, 3);
136 assert_eq!(curves.len(), 2);
137 assert_eq!(curves[0], vec![1.0, 2.0, 3.0]);
138 assert_eq!(curves[1], vec![4.0, 5.0, 6.0]);
139 }
140
141 #[test]
142 fn test_l2_distance_identical() {
143 let curve = vec![1.0, 2.0, 3.0];
144 let weights = vec![0.25, 0.5, 0.25];
145 let dist = l2_distance(&curve, &curve, &weights);
146 assert!(dist.abs() < NUMERICAL_EPS);
147 }
148
149 #[test]
150 fn test_l2_distance_different() {
151 let curve1 = vec![0.0, 0.0, 0.0];
152 let curve2 = vec![1.0, 1.0, 1.0];
153 let weights = vec![0.25, 0.5, 0.25]; let dist = l2_distance(&curve1, &curve2, &weights);
155 assert!((dist - 1.0).abs() < NUMERICAL_EPS);
157 }
158}