1use crate::numbers::Numeric;
2use std::ops::{Add, Mul};
3
4pub trait VectorOps<T>
5where
6 T: Numeric + Default + Mul<Output = T> + Add<Output = T> + Clone,
7{
8 fn dot_product(&self, b: &[T]) -> Option<T>;
14
15 fn squared_norm(&self) -> T;
17
18 fn shrink(&self, scalar: f64) -> Option<Vec<f64>>;
27
28 fn stretch<U>(&self, scalar: U) -> Option<Vec<f64>>
40 where
41 U: Into<f64> + PartialOrd + Copy;
42}
43impl<T> VectorOps<T> for Vec<T>
44where
45 T: Numeric + Default + Mul<Output = T> + Add<Output = T> + Clone,
46{
47 fn dot_product(&self, b: &[T]) -> Option<T> {
53 if self.len() != b.len() {
56 return None;
57 }
58
59 Some(self.iter().zip(b).fold(T::default(), |acc, (ai, bi)| {
62 (ai.clone() * bi.clone()) + acc
63 }))
64 }
65
66 fn squared_norm(&self) -> T {
68 self.iter()
69 .fold(T::default(), |acc, x| (x.clone() * x.clone()) + acc)
70 }
71
72 fn shrink(&self, scalar: f64) -> Option<Vec<f64>> {
81 if !(0.0..1.0).contains(&scalar) {
84 return None;
85 }
86
87 let shrunken_vector = self.iter().map(|x| x.as_f64() * scalar).collect();
88
89 Some(shrunken_vector)
90 }
91
92 fn stretch<U>(&self, scalar: U) -> Option<Vec<f64>>
104 where
105 U: Into<f64> + PartialOrd + Copy,
106 {
107 let scalar: f64 = scalar.into();
108
109 if (0.0..1.0).contains(&scalar) {
112 return None;
113 }
114
115 let stretched_vector = self.iter().map(|x| x.as_f64() * scalar).collect();
116
117 Some(stretched_vector)
118 }
119}
120
121#[cfg(test)]
122mod tests {
123 use super::*;
124
125 #[test]
126 fn test_dot_product_integers() {
127 let vec1 = vec![1, 2, 3];
128 let vec2 = vec![4, 5, 6];
129 let result = vec1.dot_product(&vec2).unwrap();
130 assert_eq!(result, 32);
131 }
132
133 #[test]
134 fn test_dot_product_floats() {
135 let vec1 = vec![1.0, 2.0, 3.0];
136 let vec2 = vec![4.0, 5.0, 6.0];
137 let result = vec1.dot_product(&vec2).unwrap();
138 assert!(((result - 32.0) as f32).abs() < f32::EPSILON);
139 }
140
141 #[test]
142 fn test_dot_product_empty_vectors() {
143 let vec1: Vec<i32> = vec![];
144 let vec2: Vec<i32> = vec![];
145 let result = vec1.dot_product(&vec2).unwrap();
146 assert_eq!(result, 0);
147 }
148
149 #[test]
150 fn test_dot_product_mismatched_lengths() {
151 let vec1 = vec![1, 2];
152 let vec2 = vec![3, 4, 5];
153 let result = vec1.dot_product(&vec2);
154 assert_eq!(result, None);
155 }
156
157 #[test]
158 fn test_dot_product_single_element() {
159 let vec1 = vec![7];
160 let vec2 = vec![3];
161 let result = vec1.dot_product(&vec2).unwrap();
162 assert_eq!(result, 21);
163 }
164
165 #[test]
166 fn test_dot_product_with_zeros() {
167 let vec1 = vec![0, 0, 0];
168 let vec2 = vec![1, 2, 3];
169 let result = vec1.dot_product(&vec2).unwrap();
170 assert_eq!(result, 0);
171 }
172
173 #[test]
174 fn test_dot_product_negative_numbers() {
175 let vec1 = vec![-1, -2, -3];
176 let vec2 = vec![4, 5, 6];
177 let result = vec1.dot_product(&vec2).unwrap();
178 assert_eq!(result, -32);
179 }
180
181 #[test]
182 fn test_squared_norm_empty() {
183 let v: Vec<i32> = vec![];
184 assert_eq!(v.squared_norm(), 0);
185 }
186
187 #[test]
188 fn test_squared_norm_single_element() {
189 let v = vec![5];
190 assert_eq!(v.squared_norm(), 25);
191 }
192
193 #[test]
194 fn test_squared_norm_multiple_integers() {
195 let v = vec![2, -3, 4];
196 assert_eq!(v.squared_norm(), 29);
197 }
198
199 #[test]
200 fn test_squared_norm_with_negatives() {
201 let v = vec![-1, -2, -3];
202 assert_eq!(v.squared_norm(), 14);
203 }
204
205 #[test]
206 fn test_squared_norm_large_values() {
207 let v = vec![1000, 2000, 3000];
208 assert_eq!(v.squared_norm(), 14_000_000);
209 }
210
211 #[test]
212 fn test_squared_norm_floats() {
213 let v = vec![1.0_f64, 2.5_f64, 3.2_f64];
214 let result = v.squared_norm();
215 let expected = 17.49;
216 let epsilon = 1e-10;
217 assert!((result - expected).abs() < epsilon);
218 }
219
220 #[test]
221 fn test_shrink_invalid_scalar() {
222 let v = vec![1_i32, 2, 3];
223 assert_eq!(v.shrink(1.0), None);
225
226 assert_eq!(v.shrink(-0.1), None);
228 }
229
230 #[test]
231 fn test_shrink_i8() {
232 let v: Vec<i8> = vec![10, 20, 30];
233 let scalar = 0.5;
234 let result = v.shrink(scalar).expect("Expected valid shrink result");
235 assert_eq!(result, vec![5.0, 10.0, 15.0]);
237 }
238
239 #[test]
240 fn test_shrink_i32() {
241 let v: Vec<i32> = vec![1000, 2000, 3000];
242 let scalar = 0.2;
243 let result = v.shrink(scalar).expect("Expected valid shrink result");
244 assert_eq!(result, vec![200.0, 400.0, 600.0]);
245 }
246
247 #[test]
248 fn test_shrink_i64() {
249 let v: Vec<i64> = vec![1000, 2000, 3000];
250 let scalar = 0.1;
251 let result = v.shrink(scalar).expect("Expected valid shrink result");
252 assert_eq!(result, vec![100.0, 200.0, 300.0]);
253 }
254
255 #[test]
256 fn test_shrink_u64() {
257 let v: Vec<u64> = vec![1000, 2000, 3000];
258 let scalar = 0.1;
259 let result = v.shrink(scalar).expect("Expected valid shrink result");
260 assert_eq!(result, vec![100.0, 200.0, 300.0]);
261 }
262
263 #[test]
264 fn test_shrink_f32() {
265 let v: Vec<f32> = vec![10.0, 20.0, 30.0];
266 let scalar = 0.5;
267 let result = v.shrink(scalar).expect("Expected valid shrink result");
268 assert_eq!(result, vec![5.0, 10.0, 15.0]);
269 }
270
271 #[test]
272 fn test_shrink_f64() {
273 let v: Vec<f64> = vec![10.0, 20.0, 30.0];
274 let scalar = 0.5;
275 let result = v.shrink(scalar).expect("Expected valid shrink result");
276 assert_eq!(result, vec![5.0, 10.0, 15.0]);
277 }
278
279 #[test]
280 fn test_stretch_with_scalar_in_range_returns_none() {
281 let vec: Vec<f64> = vec![1.0, 2.0, 3.0];
282 assert_eq!(vec.stretch(0.5), None);
283 }
284
285 #[test]
286 fn test_stretch_with_scalar_equal_to_one_returns_same_vector() {
287 let vec: Vec<f64> = vec![1.0, 2.0, 3.0];
288 let expected: Vec<f64> = vec![1.0, 2.0, 3.0];
289 assert_eq!(vec.stretch(1.0), Some(expected));
290 }
291
292 #[test]
293 fn test_stretch_with_scalar_greater_than_one() {
294 let vec: Vec<f64> = vec![1.0, 2.0, 3.0];
295 let scalar = 2.0;
296 let expected: Vec<f64> = vec![2.0, 4.0, 6.0];
297 assert_eq!(vec.stretch(scalar), Some(expected));
298 }
299
300 #[test]
301 fn test_stretch_with_integer_scalar() {
302 let vec: Vec<f64> = vec![1.0, 2.0, 3.0];
303 let scalar = 3;
304 let expected: Vec<f64> = vec![3.0, 6.0, 9.0];
305 assert_eq!(vec.stretch(scalar), Some(expected));
306 }
307
308 #[test]
309 fn test_stretch_with_negative_scalar() {
310 let vec: Vec<f64> = vec![1.0, 2.0, 3.0];
311 let scalar = -2.0;
312 let expected: Vec<f64> = vec![-2.0, -4.0, -6.0];
313 assert_eq!(vec.stretch(scalar), Some(expected));
314 }
315}