1#[derive(Clone, Debug, PartialEq)]
13pub struct Point {
14 dims: Vec<f32>,
15}
16
17impl Point {
18 pub fn new(dims: Vec<f32>) -> Self {
27 Self { dims }
28 }
29
30 pub fn origin(dims: usize) -> Self {
40 Self {
41 dims: vec![0.0; dims],
42 }
43 }
44
45 pub fn dimensionality(&self) -> usize {
47 self.dims.len()
48 }
49
50 pub fn dims(&self) -> &[f32] {
52 &self.dims
53 }
54
55 pub fn dims_mut(&mut self) -> &mut [f32] {
57 &mut self.dims
58 }
59
60 pub fn magnitude(&self) -> f32 {
69 self.dims.iter().map(|x| x * x).sum::<f32>().sqrt()
70 }
71
72 pub fn is_normalized(&self) -> bool {
74 let mag = self.magnitude();
75 (mag - 1.0).abs() < 0.001
76 }
77
78 pub fn normalize(&self) -> Self {
90 let mag = self.magnitude();
91 if mag == 0.0 {
92 return self.clone();
93 }
94 Self {
95 dims: self.dims.iter().map(|x| x / mag).collect(),
96 }
97 }
98
99 pub fn add(&self, other: &Point) -> Self {
101 assert_eq!(
102 self.dimensionality(),
103 other.dimensionality(),
104 "Points must have same dimensionality"
105 );
106 Self {
107 dims: self
108 .dims
109 .iter()
110 .zip(other.dims.iter())
111 .map(|(a, b)| a + b)
112 .collect(),
113 }
114 }
115
116 pub fn scale(&self, scalar: f32) -> Self {
118 Self {
119 dims: self.dims.iter().map(|x| x * scalar).collect(),
120 }
121 }
122}
123
124#[cfg(test)]
125mod tests {
126 use super::*;
127
128 #[test]
129 fn test_new_point() {
130 let p = Point::new(vec![1.0, 2.0, 3.0]);
131 assert_eq!(p.dimensionality(), 3);
132 assert_eq!(p.dims(), &[1.0, 2.0, 3.0]);
133 }
134
135 #[test]
136 fn test_origin() {
137 let origin = Point::origin(768);
138 assert_eq!(origin.dimensionality(), 768);
139 assert!(origin.dims().iter().all(|&x| x == 0.0));
140 }
141
142 #[test]
143 fn test_magnitude() {
144 let p = Point::new(vec![3.0, 4.0]);
145 assert!((p.magnitude() - 5.0).abs() < 0.0001);
146 }
147
148 #[test]
149 fn test_normalize() {
150 let p = Point::new(vec![3.0, 4.0]);
151 let normalized = p.normalize();
152 assert!(normalized.is_normalized());
153 assert!((normalized.dims()[0] - 0.6).abs() < 0.0001);
154 assert!((normalized.dims()[1] - 0.8).abs() < 0.0001);
155 }
156
157 #[test]
158 fn test_normalize_zero() {
159 let p = Point::origin(3);
160 let normalized = p.normalize();
161 assert_eq!(normalized.dims(), &[0.0, 0.0, 0.0]);
162 }
163
164 #[test]
165 fn test_add() {
166 let a = Point::new(vec![1.0, 2.0]);
167 let b = Point::new(vec![3.0, 4.0]);
168 let c = a.add(&b);
169 assert_eq!(c.dims(), &[4.0, 6.0]);
170 }
171
172 #[test]
173 fn test_scale() {
174 let p = Point::new(vec![1.0, 2.0]);
175 let scaled = p.scale(2.0);
176 assert_eq!(scaled.dims(), &[2.0, 4.0]);
177 }
178
179 #[test]
180 #[should_panic(expected = "same dimensionality")]
181 fn test_add_different_dims_panics() {
182 let a = Point::new(vec![1.0, 2.0]);
183 let b = Point::new(vec![1.0, 2.0, 3.0]);
184 let _ = a.add(&b);
185 }
186}