1use num_traits::{Num, NumCast};
2
3#[derive(Debug, Clone, Copy)]
4pub enum TransformType {
6 Sqrt,
12
13 Log,
19
20 Tanh,
26}
27
28pub fn apply_transform<T>(data: &[T], transform_type: TransformType) -> Vec<f64>
43where
44 T: Num + NumCast + Copy,
45{
46 match transform_type {
47 TransformType::Sqrt => sqrt_transform(data),
48 TransformType::Log => log_transform(data),
49 TransformType::Tanh => tanh_transform(data),
50 }
51}
52
53pub fn sqrt_transform<T>(data: &[T]) -> Vec<f64>
70where
71 T: Num + NumCast + Copy,
72{
73 if data.is_empty() {
74 return Vec::new();
75 }
76
77 data.iter()
78 .filter_map(|&x| NumCast::from(x).map(f64::sqrt))
79 .collect()
80}
81
82pub fn log_transform<T>(data: &[T]) -> Vec<f64>
103where
104 T: Num + NumCast + Copy,
105{
106 if data.is_empty() {
107 return Vec::new();
108 }
109
110 data.iter()
111 .filter_map(|&x| {
112 let x_f: f64 = NumCast::from(x)?;
113 if x_f > 0.0 { Some(x_f.ln()) } else { None }
114 })
115 .collect()
116}
117
118pub fn tanh_transform<T>(data: &[T]) -> Vec<f64>
133where
134 T: Num + NumCast + Copy,
135{
136 if data.is_empty() {
137 return Vec::new();
138 }
139
140 data.iter()
141 .filter_map(|&x| NumCast::from(x).map(f64::tanh))
142 .collect()
143}
144
145#[cfg(test)]
146mod tests {
147 use super::*;
148
149 fn assert_close(a: f64, b: f64, eps: f64) {
150 assert!(
151 (a - b).abs() < eps,
152 "Expected {:.6}, got {:.6}, diff = {:.6}",
153 b,
154 a,
155 (a - b).abs()
156 );
157 }
158
159 #[test]
160 fn test_sqrt_transform_with_f64() {
161 let data = vec![0.0, 1.0, 4.0, 9.0, 16.0];
162 let expected = [0.0, 1.0, 2.0, 3.0, 4.0];
163 let result = sqrt_transform(&data);
164
165 for (a, b) in result.into_iter().zip(expected.into_iter()) {
166 assert_close(a, b, 1e-6);
167 }
168 }
169
170 #[test]
171 fn test_sqrt_transform_with_u32() {
172 let data = vec![0u32, 1, 4, 9, 16, 25];
173 let expected = [0.0, 1.0, 2.0, 3.0, 4.0, 5.0];
174 let result = sqrt_transform(&data);
175
176 for (a, b) in result.into_iter().zip(expected.into_iter()) {
177 assert_close(a, b, 1e-6);
178 }
179 }
180
181 #[test]
182 fn test_sqrt_transform_with_empty_input() {
183 let data: Vec<u32> = vec![];
184 let result = sqrt_transform(&data);
185 assert!(result.is_empty());
186 }
187
188 #[test]
189 fn test_sqrt_transform_skips_unconvertible_values() {
190 let data = vec![1u8, 4u8, 9u8];
191 let result = sqrt_transform(&data);
192 assert_eq!(result.len(), 3);
193 }
194
195 #[test]
196 fn test_log_transform_with_f64() {
197 let data = vec![1.0, std::f64::consts::E, 10.0, 100.0];
198 let expected = [0.0, 1.0, 10.0_f64.ln(), 100.0_f64.ln()];
199 let result = log_transform(&data);
200
201 for (a, b) in result.iter().zip(expected.iter()) {
202 assert_close(*a, *b, 1e-10);
203 }
204 }
205
206 #[test]
207 fn test_log_transform_with_u32() {
208 let data = vec![1u32, 2, 10, 100];
209 let expected = vec![1.0, 2.0, 10.0, 100.0]
210 .into_iter()
211 .map(f64::ln)
212 .collect::<Vec<_>>();
213 let result = log_transform(&data);
214
215 for (a, b) in result.iter().zip(expected.iter()) {
216 assert_close(*a, *b, 1e-10);
217 }
218 }
219
220 #[test]
221 fn test_log_transform_skips_zeros_and_negatives() {
222 let data = vec![0.0, -1.0, -100.0, 1.0];
223 let result = log_transform(&data);
224 assert_eq!(result.len(), 1);
225 assert_close(result[0], 0.0, 1e-10);
226 }
227
228 #[test]
229 fn test_log_transform_empty_input() {
230 let data: Vec<f64> = vec![];
231 let result = log_transform(&data);
232 assert!(result.is_empty());
233 }
234
235 #[test]
236 fn test_tanh_transform_with_f64() {
237 let data: Vec<f64> = vec![0.0, 1.0, -1.0, 10.0, -10.0];
238 let expected: Vec<f64> = data.iter().map(|x| x.tanh()).collect();
239 let result = tanh_transform(&data);
240
241 for (a, b) in result.iter().zip(expected.iter()) {
242 assert_close(*a, *b, 1e-6);
243 }
244 }
245
246 #[test]
247 fn test_tanh_transform_with_integers() {
248 let data = vec![-3, -1, 0, 1, 3];
249 let expected: Vec<f64> = data.iter().map(|&x| (x as f64).tanh()).collect();
250 let result = tanh_transform(&data);
251
252 for (a, b) in result.iter().zip(expected.iter()) {
253 assert_close(*a, *b, 1e-6);
254 }
255 }
256
257 #[test]
258 fn test_tanh_transform_extremes() {
259 let data = vec![1000.0, -1000.0];
260 let result = tanh_transform(&data);
261 assert_close(result[0], 1.0, 1e-6);
262 assert_close(result[1], -1.0, 1e-6);
263 }
264
265 #[test]
266 fn test_tanh_transform_empty_input() {
267 let data: Vec<f64> = vec![];
268 let result = tanh_transform(&data);
269 assert!(result.is_empty());
270 }
271}