ceylon_next/memory/vector/
utils.rs1pub fn cosine_similarity(a: &[f32], b: &[f32]) -> Result<f32, String> {
30 if a.len() != b.len() {
31 return Err(format!(
32 "Vector dimensions mismatch: {} vs {}",
33 a.len(),
34 b.len()
35 ));
36 }
37
38 if a.is_empty() {
39 return Err("Cannot compute similarity of empty vectors".to_string());
40 }
41
42 let dot_product: f32 = a.iter().zip(b.iter()).map(|(x, y)| x * y).sum();
43
44 let magnitude_a: f32 = a.iter().map(|x| x * x).sum::<f32>().sqrt();
45 let magnitude_b: f32 = b.iter().map(|x| x * x).sum::<f32>().sqrt();
46
47 if magnitude_a == 0.0 || magnitude_b == 0.0 {
48 return Ok(0.0);
49 }
50
51 Ok(dot_product / (magnitude_a * magnitude_b))
52}
53
54pub fn normalize_vector(vector: &mut [f32]) {
74 let magnitude: f32 = vector.iter().map(|x| x * x).sum::<f32>().sqrt();
75
76 if magnitude > 0.0 {
77 for x in vector.iter_mut() {
78 *x /= magnitude;
79 }
80 }
81}
82
83pub fn euclidean_distance(a: &[f32], b: &[f32]) -> Result<f32, String> {
94 if a.len() != b.len() {
95 return Err(format!(
96 "Vector dimensions mismatch: {} vs {}",
97 a.len(),
98 b.len()
99 ));
100 }
101
102 let sum: f32 = a
103 .iter()
104 .zip(b.iter())
105 .map(|(x, y)| {
106 let diff = x - y;
107 diff * diff
108 })
109 .sum();
110
111 Ok(sum.sqrt())
112}
113
114pub fn dot_product(a: &[f32], b: &[f32]) -> Result<f32, String> {
125 if a.len() != b.len() {
126 return Err(format!(
127 "Vector dimensions mismatch: {} vs {}",
128 a.len(),
129 b.len()
130 ));
131 }
132
133 Ok(a.iter().zip(b.iter()).map(|(x, y)| x * y).sum())
134}
135
136#[cfg(test)]
137mod tests {
138 use super::*;
139
140 #[test]
141 fn test_cosine_similarity_identical() {
142 let v = vec![1.0, 2.0, 3.0];
143 let sim = cosine_similarity(&v, &v).unwrap();
144 assert!((sim - 1.0).abs() < 1e-6);
145 }
146
147 #[test]
148 fn test_cosine_similarity_orthogonal() {
149 let v1 = vec![1.0, 0.0];
150 let v2 = vec![0.0, 1.0];
151 let sim = cosine_similarity(&v1, &v2).unwrap();
152 assert!((sim - 0.0).abs() < 1e-6);
153 }
154
155 #[test]
156 fn test_cosine_similarity_opposite() {
157 let v1 = vec![1.0, 0.0];
158 let v2 = vec![-1.0, 0.0];
159 let sim = cosine_similarity(&v1, &v2).unwrap();
160 assert!((sim - (-1.0)).abs() < 1e-6);
161 }
162
163 #[test]
164 fn test_normalize_vector() {
165 let mut v = vec![3.0, 4.0];
166 normalize_vector(&mut v);
167 assert!((v[0] - 0.6).abs() < 1e-6);
168 assert!((v[1] - 0.8).abs() < 1e-6);
169
170 let magnitude: f32 = v.iter().map(|x| x * x).sum::<f32>().sqrt();
172 assert!((magnitude - 1.0).abs() < 1e-6);
173 }
174
175 #[test]
176 fn test_euclidean_distance() {
177 let v1 = vec![1.0, 2.0];
178 let v2 = vec![4.0, 6.0];
179 let dist = euclidean_distance(&v1, &v2).unwrap();
180 assert!((dist - 5.0).abs() < 1e-6);
181 }
182
183 #[test]
184 fn test_dot_product() {
185 let v1 = vec![1.0, 2.0, 3.0];
186 let v2 = vec![4.0, 5.0, 6.0];
187 let dot = dot_product(&v1, &v2).unwrap();
188 assert!((dot - 32.0).abs() < 1e-6); }
190
191 #[test]
192 fn test_dimension_mismatch() {
193 let v1 = vec![1.0, 2.0];
194 let v2 = vec![1.0, 2.0, 3.0];
195 assert!(cosine_similarity(&v1, &v2).is_err());
196 assert!(euclidean_distance(&v1, &v2).is_err());
197 assert!(dot_product(&v1, &v2).is_err());
198 }
199}