1use crate::ambient_space::{AffineSpace, common_space};
2
3use super::*;
4use algebraeon_rings::matrix::{Matrix, MatrixStructure};
5use std::borrow::Borrow;
6use std::hash::Hash;
7
8#[derive(Clone)]
9pub struct Vector<'f, FS: FieldSignature + 'f> {
10 ambient_space: AffineSpace<'f, FS>,
11 coordinates: Vec<FS::Set>, }
13
14impl<'f, FS: FieldSignature> std::fmt::Debug for Vector<'f, FS> {
15 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
16 f.debug_struct("Vector")
17 .field("coordinates", &self.coordinates)
18 .finish()
19 }
20}
21
22impl<'f, FS: FieldSignature> PartialEq for Vector<'f, FS> {
23 fn eq(&self, other: &Self) -> bool {
24 match common_space(self.ambient_space, other.ambient_space) {
25 Some(space) => {
26 let n = space.linear_dimension().unwrap();
27 (0..n).all(|i| space.field().equal(self.coordinate(i), other.coordinate(i)))
28 }
29 None => false,
30 }
31 }
32}
33
34impl<'f, FS: FieldSignature> Eq for Vector<'f, FS> {}
35
36impl<'f, FS: FieldSignature> Hash for Vector<'f, FS>
37where
38 FS::Set: Hash,
39{
40 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
41 self.coordinates.hash(state);
43 }
44}
45impl<'f, FS: FieldSignature> Vector<'f, FS> {
46 pub fn ambient_space(&self) -> AffineSpace<'f, FS> {
47 self.ambient_space
48 }
49
50 fn new(
51 ambient_space: AffineSpace<'f, FS>,
52 coordinates: impl IntoIterator<Item = impl Into<FS::Set>>,
53 ) -> Self {
54 let coordinates = coordinates
55 .into_iter()
56 .map(|c| c.into())
57 .collect::<Vec<_>>();
58 assert_eq!(ambient_space.linear_dimension().unwrap(), coordinates.len());
59 Self {
60 ambient_space,
61 coordinates,
62 }
63 }
64
65 pub fn construct(
66 ambient_space: AffineSpace<'f, FS>,
67 coordinate_func: impl FnMut(usize) -> FS::Set,
68 ) -> Self {
69 let coordinates = (0..ambient_space.borrow().linear_dimension().unwrap())
70 .map(coordinate_func)
71 .collect();
72 Self {
73 ambient_space,
74 coordinates,
75 }
76 }
77
78 pub fn zero(ambient_space: AffineSpace<'f, FS>) -> Self {
79 let field = ambient_space.borrow().field().clone();
80 Self::construct(ambient_space, |_i| field.zero())
81 }
82
83 pub fn coordinate(&self, i: usize) -> &FS::Set {
84 self.coordinates.get(i).unwrap()
85 }
86
87 pub fn coordinate_mut(&mut self, i: usize) -> &mut FS::Set {
88 self.coordinates.get_mut(i).unwrap()
89 }
90
91 pub fn into_coordinates(self) -> Vec<FS::Set> {
92 self.coordinates
93 }
94
95 pub fn into_row(&self) -> Matrix<FS::Set> {
96 Matrix::construct(
97 1,
98 self.ambient_space().linear_dimension().unwrap(),
99 |_r, c| self.coordinate(c).clone(),
100 )
101 }
102
103 pub fn into_col(&self) -> Matrix<FS::Set> {
104 Matrix::construct(
105 self.ambient_space().linear_dimension().unwrap(),
106 1,
107 |r, _c| self.coordinate(r).clone(),
108 )
109 }
110}
111
112impl<'f, FS: FieldSignature> AffineSpace<'f, FS> {
113 pub fn vector(
114 self,
115 coordinates: impl IntoIterator<Item = impl Into<FS::Set>>,
116 ) -> Vector<'f, FS> {
117 Vector::new(self, coordinates)
118 }
119
120 pub fn rows_from_vectors(&self, vecs: Vec<&Vector<'f, FS>>) -> Matrix<FS::Set> {
121 for vec in &vecs {
122 assert_eq!(*self, vec.ambient_space());
123 }
124 Matrix::construct(vecs.len(), self.linear_dimension().unwrap(), |r, c| {
125 vecs[r].coordinate(c).clone()
126 })
127 }
128
129 pub fn cols_from_vectors(&self, vecs: Vec<&Vector<'f, FS>>) -> Matrix<FS::Set> {
130 self.rows_from_vectors(vecs).transpose()
131 }
132
133 pub fn vectors_from_rows(self, mat: &Matrix<FS::Set>) -> Vec<Vector<'f, FS>> {
134 assert_eq!(mat.cols(), self.linear_dimension().unwrap());
135 (0..mat.rows())
136 .map(|r| Vector::new(self, (0..mat.cols()).map(|c| mat.at(r, c).unwrap().clone())))
137 .collect()
138 }
139
140 pub fn vectors_from_cols(self, mat: &Matrix<FS::Set>) -> Vec<Vector<'f, FS>> {
141 assert_eq!(mat.rows(), self.linear_dimension().unwrap());
142 self.vectors_from_rows(&mat.transpose_ref())
143 }
144
145 pub fn vector_from_row(self, mat: &Matrix<FS::Set>) -> Vector<'f, FS> {
146 assert_eq!(mat.rows(), 1);
147 assert_eq!(mat.cols(), self.linear_dimension().unwrap());
148 self.vectors_from_rows(mat).pop().unwrap()
149 }
150
151 pub fn vector_from_col(self, mat: &Matrix<FS::Set>) -> Vector<'f, FS> {
152 assert_eq!(mat.rows(), self.linear_dimension().unwrap());
153 assert_eq!(mat.cols(), 1);
154 self.vector_from_row(&mat.transpose_ref())
155 }
156
157 pub fn are_points_affine_independent(&self, points: Vec<&Vector<'f, FS>>) -> bool {
158 for point in &points {
159 assert_eq!(*self, point.ambient_space());
160 }
161 if points.is_empty() {
162 true
163 } else {
164 let vecs = (1..points.len())
165 .map(|i| points[i] - points[0])
166 .collect::<Vec<_>>();
167 let mat = self.rows_from_vectors(vecs.iter().collect());
168 MatrixStructure::new(self.field().clone()).rank(mat) == vecs.len()
169 }
170 }
171
172 pub fn determinant(&self, vecs: Vec<&Vector<'f, FS>>) -> FS::Set {
173 MatrixStructure::new(self.field().clone())
174 .det(self.rows_from_vectors(vecs))
175 .unwrap()
176 }
177
178 pub fn rank(&self, vecs: Vec<&Vector<'f, FS>>) -> usize {
179 MatrixStructure::new(self.field().clone()).rank(self.rows_from_vectors(vecs))
180 }
181}
182
183impl<'f, FS: FieldSignature> std::ops::Neg for &Vector<'f, FS> {
185 type Output = Vector<'f, FS>;
186
187 fn neg(self) -> Self::Output {
188 Vector {
189 ambient_space: self.ambient_space,
190 coordinates: self
191 .coordinates
192 .iter()
193 .map(|x| self.ambient_space().field().neg(x))
194 .collect(),
195 }
196 }
197}
198
199impl<'f, FS: FieldSignature> std::ops::Add<&Vector<'f, FS>> for &Vector<'f, FS> {
201 type Output = Vector<'f, FS>;
202
203 fn add(self, other: &Vector<'f, FS>) -> Self::Output {
204 match common_space(self.ambient_space, other.ambient_space) {
205 Some(space) => {
206 let n = space.linear_dimension().unwrap();
207 let coordinates = (0..n)
208 .map(|i| space.field().add(self.coordinate(i), other.coordinate(i)))
209 .collect();
210 Vector {
211 ambient_space: space,
212 coordinates,
213 }
214 }
215 None => panic!("Can't add vectors belonging to different spaces"),
216 }
217 }
218}
219
220impl<'f, FS: FieldSignature> std::ops::AddAssign<&Vector<'f, FS>> for Vector<'f, FS> {
222 fn add_assign(&mut self, other: &Vector<'f, FS>) {
223 match common_space(self.ambient_space, other.ambient_space) {
224 Some(space) => {
225 let n = space.borrow().linear_dimension().unwrap();
226 for i in 0..n {
227 space
228 .field()
229 .add_mut(self.coordinate_mut(i), other.coordinate(i));
230 }
231 }
232 None => panic!("Can't add vectors belonging to different spaces"),
233 }
234 }
235}
236
237impl<'f, FS: FieldSignature> std::ops::Sub<&Vector<'f, FS>> for &Vector<'f, FS> {
239 type Output = Vector<'f, FS>;
240
241 fn sub(self, other: &Vector<'f, FS>) -> Self::Output {
242 self + &(-other)
243 }
244}
245
246impl<'f, FS: FieldSignature> Vector<'f, FS> {
248 pub fn scalar_mul(&self, other: &FS::Set) -> Vector<'f, FS> {
249 Vector {
250 ambient_space: self.ambient_space,
251 coordinates: self
252 .coordinates
253 .iter()
254 .map(|x| self.ambient_space().field().mul(x, other))
255 .collect(),
256 }
257 }
258}
259
260impl<'f, FS: OrderedRingSignature + FieldSignature> PartialOrd for Vector<'f, FS> {
263 fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
264 Some(self.cmp(other))
265 }
266}
267impl<'f, FS: OrderedRingSignature + FieldSignature> Ord for Vector<'f, FS> {
268 fn cmp(&self, other: &Self) -> std::cmp::Ordering {
269 let space = common_space(self.ambient_space(), other.ambient_space()).unwrap();
270 for i in 0..space.linear_dimension().unwrap() {
271 match space
272 .field()
273 .ring_cmp(self.coordinate(i), other.coordinate(i))
274 {
275 std::cmp::Ordering::Less => {
276 return std::cmp::Ordering::Less;
277 }
278 std::cmp::Ordering::Equal => {}
279 std::cmp::Ordering::Greater => {
280 return std::cmp::Ordering::Greater;
281 }
282 }
283 }
284 std::cmp::Ordering::Equal
285 }
286}
287
288pub trait DotProduct<Other> {
289 type Output;
290
291 fn dot(self, other: Other) -> Self::Output;
292}
293
294impl<'f, FS: FieldSignature> DotProduct<&Vector<'f, FS>> for &Vector<'f, FS> {
296 type Output = FS::Set;
297
298 fn dot(self, other: &Vector<'f, FS>) -> Self::Output {
299 match common_space(self.ambient_space, other.ambient_space) {
300 Some(space) => {
301 let n = space.linear_dimension().unwrap();
302 space.field().sum(
303 (0..n)
304 .map(|i| space.field().mul(self.coordinate(i), other.coordinate(i)))
305 .collect(),
306 )
307 }
308 None => panic!("Can't add vectors belonging to different spaces"),
309 }
310 }
311}
312
313#[cfg(test)]
314mod tests {
315 use super::*;
316 use algebraeon_nzq::Rational;
317
318 #[test]
319 fn vector_from_mat() {
320 let space = AffineSpace::new_linear(Rational::structure_ref(), 2);
321 let mat = Matrix::<Rational>::from_rows(vec![
322 vec![Rational::from(1), Rational::from(2)],
323 vec![Rational::from(3), Rational::from(4)],
324 ]);
325
326 mat.pprint();
327
328 let mut vecs = space.vectors_from_rows(&mat);
329 let v2 = vecs.pop().unwrap();
330 let v1 = vecs.pop().unwrap();
331 println!("v1 = {v1:?}");
332 println!("v2 = {v2:?}");
333
334 assert_eq!(
335 v1,
336 Vector::new(space, vec![Rational::from(1), Rational::from(2)])
337 );
338 assert_eq!(
339 v2,
340 Vector::new(space, vec![Rational::from(3), Rational::from(4)])
341 );
342 }
343
344 #[test]
345 fn det() {
346 let space = AffineSpace::new_linear(Rational::structure_ref(), 2);
347 let v1 = Vector::new(space, vec![Rational::from(3), Rational::from(2)]);
348 let v2 = Vector::new(space, vec![Rational::from(5), Rational::from(7)]);
349 assert_eq!(space.determinant(vec![&v1, &v2]), Rational::from(11));
350 }
351
352 #[test]
353 fn test_abgroup() {
354 let space_ab = AffineSpace::new_linear(Rational::structure_ref(), 2);
355 let a = Vector::new(space_ab, vec![Rational::from(1), Rational::from(2)]);
356 let b = Vector::new(space_ab, vec![Rational::from(6), Rational::from(3)]);
357 let c = Vector::new(space_ab, vec![Rational::from(7), Rational::from(5)]);
358
359 let space_xy = AffineSpace::new_linear(Rational::structure_ref(), 2);
360 let x = Vector::new(space_xy, vec![Rational::from(1), Rational::from(2)]);
361 let y = Vector::new(space_xy, vec![Rational::from(6), Rational::from(3)]);
362 let z = Vector::new(space_xy, vec![Rational::from(7), Rational::from(5)]);
363 let w = Vector::new(space_xy, vec![Rational::from(-2), Rational::from(-4)]);
364
365 assert_eq!(c, &a + &b);
366 assert_eq!(z, &x + &y);
367 assert_eq!(a, a);
368 assert_ne!(a, b);
369 assert_ne!(a, x); assert_ne!(x.scalar_mul(&Rational::from(-2)), z);
371 assert_eq!(x.scalar_mul(&Rational::from(-2)), w);
372 }
373}