1pub const NUMERICAL_EPS: f64 = 1e-10;
5
6pub const DEFAULT_CONVERGENCE_TOL: f64 = 1e-6;
8
9pub fn extract_curves(data: &crate::matrix::FdMatrix) -> Vec<Vec<f64>> {
20 data.rows()
21}
22
23pub fn l2_distance(curve1: &[f64], curve2: &[f64], weights: &[f64]) -> f64 {
33 let mut dist_sq = 0.0;
34 for i in 0..curve1.len() {
35 let diff = curve1[i] - curve2[i];
36 dist_sq += diff * diff * weights[i];
37 }
38 dist_sq.sqrt()
39}
40
41pub fn simpsons_weights(argvals: &[f64]) -> Vec<f64> {
51 let n = argvals.len();
52 if n < 2 {
53 return vec![1.0; n];
54 }
55
56 let mut weights = vec![0.0; n];
57
58 if n == 2 {
59 let h = argvals[1] - argvals[0];
61 weights[0] = h / 2.0;
62 weights[1] = h / 2.0;
63 return weights;
64 }
65
66 for i in 0..n {
68 if i == 0 {
69 weights[i] = (argvals[1] - argvals[0]) / 2.0;
70 } else if i == n - 1 {
71 weights[i] = (argvals[n - 1] - argvals[n - 2]) / 2.0;
72 } else {
73 weights[i] = (argvals[i + 1] - argvals[i - 1]) / 2.0;
74 }
75 }
76
77 weights
78}
79
80pub fn simpsons_weights_2d(argvals_s: &[f64], argvals_t: &[f64]) -> Vec<f64> {
91 let weights_s = simpsons_weights(argvals_s);
92 let weights_t = simpsons_weights(argvals_t);
93 let m1 = argvals_s.len();
94 let m2 = argvals_t.len();
95
96 let mut weights = vec![0.0; m1 * m2];
97 for i in 0..m1 {
98 for j in 0..m2 {
99 weights[i * m2 + j] = weights_s[i] * weights_t[j];
100 }
101 }
102 weights
103}
104
105#[cfg(test)]
106mod tests {
107 use super::*;
108
109 #[test]
110 fn test_simpsons_weights_uniform() {
111 let argvals = vec![0.0, 0.25, 0.5, 0.75, 1.0];
112 let weights = simpsons_weights(&argvals);
113 let sum: f64 = weights.iter().sum();
114 assert!((sum - 1.0).abs() < NUMERICAL_EPS);
115 }
116
117 #[test]
118 fn test_simpsons_weights_2d() {
119 let argvals_s = vec![0.0, 0.5, 1.0];
120 let argvals_t = vec![0.0, 0.5, 1.0];
121 let weights = simpsons_weights_2d(&argvals_s, &argvals_t);
122 let sum: f64 = weights.iter().sum();
123 assert!((sum - 1.0).abs() < NUMERICAL_EPS);
124 }
125
126 #[test]
127 fn test_extract_curves() {
128 let data = vec![1.0, 4.0, 2.0, 5.0, 3.0, 6.0];
131 let mat = crate::matrix::FdMatrix::from_column_major(data, 2, 3).unwrap();
132 let curves = extract_curves(&mat);
133 assert_eq!(curves.len(), 2);
134 assert_eq!(curves[0], vec![1.0, 2.0, 3.0]);
135 assert_eq!(curves[1], vec![4.0, 5.0, 6.0]);
136 }
137
138 #[test]
139 fn test_l2_distance_identical() {
140 let curve = vec![1.0, 2.0, 3.0];
141 let weights = vec![0.25, 0.5, 0.25];
142 let dist = l2_distance(&curve, &curve, &weights);
143 assert!(dist.abs() < NUMERICAL_EPS);
144 }
145
146 #[test]
147 fn test_l2_distance_different() {
148 let curve1 = vec![0.0, 0.0, 0.0];
149 let curve2 = vec![1.0, 1.0, 1.0];
150 let weights = vec![0.25, 0.5, 0.25]; let dist = l2_distance(&curve1, &curve2, &weights);
152 assert!((dist - 1.0).abs() < NUMERICAL_EPS);
154 }
155}