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.field().cmp(self.coordinate(i), other.coordinate(i)) {
272 std::cmp::Ordering::Less => {
273 return std::cmp::Ordering::Less;
274 }
275 std::cmp::Ordering::Equal => {}
276 std::cmp::Ordering::Greater => {
277 return std::cmp::Ordering::Greater;
278 }
279 }
280 }
281 std::cmp::Ordering::Equal
282 }
283}
284
285pub trait DotProduct<Other> {
286 type Output;
287
288 fn dot(self, other: Other) -> Self::Output;
289}
290
291impl<'f, FS: FieldSignature> DotProduct<&Vector<'f, FS>> for &Vector<'f, FS> {
293 type Output = FS::Set;
294
295 fn dot(self, other: &Vector<'f, FS>) -> Self::Output {
296 match common_space(self.ambient_space, other.ambient_space) {
297 Some(space) => {
298 let n = space.linear_dimension().unwrap();
299 space.field().sum(
300 (0..n)
301 .map(|i| space.field().mul(self.coordinate(i), other.coordinate(i)))
302 .collect(),
303 )
304 }
305 None => panic!("Can't add vectors belonging to different spaces"),
306 }
307 }
308}
309
310#[cfg(test)]
311mod tests {
312 use super::*;
313 use algebraeon_nzq::Rational;
314
315 #[test]
316 fn vector_from_mat() {
317 let space = AffineSpace::new_linear(Rational::structure_ref(), 2);
318 let mat = Matrix::<Rational>::from_rows(vec![
319 vec![Rational::from(1), Rational::from(2)],
320 vec![Rational::from(3), Rational::from(4)],
321 ]);
322
323 mat.pprint();
324
325 let mut vecs = space.vectors_from_rows(&mat);
326 let v2 = vecs.pop().unwrap();
327 let v1 = vecs.pop().unwrap();
328 println!("v1 = {v1:?}");
329 println!("v2 = {v2:?}");
330
331 assert_eq!(
332 v1,
333 Vector::new(space, vec![Rational::from(1), Rational::from(2)])
334 );
335 assert_eq!(
336 v2,
337 Vector::new(space, vec![Rational::from(3), Rational::from(4)])
338 );
339 }
340
341 #[test]
342 fn det() {
343 let space = AffineSpace::new_linear(Rational::structure_ref(), 2);
344 let v1 = Vector::new(space, vec![Rational::from(3), Rational::from(2)]);
345 let v2 = Vector::new(space, vec![Rational::from(5), Rational::from(7)]);
346 assert_eq!(space.determinant(vec![&v1, &v2]), Rational::from(11));
347 }
348
349 #[test]
350 fn test_abgroup() {
351 let space_ab = AffineSpace::new_linear(Rational::structure_ref(), 2);
352 let a = Vector::new(space_ab, vec![Rational::from(1), Rational::from(2)]);
353 let b = Vector::new(space_ab, vec![Rational::from(6), Rational::from(3)]);
354 let c = Vector::new(space_ab, vec![Rational::from(7), Rational::from(5)]);
355
356 let space_xy = AffineSpace::new_linear(Rational::structure_ref(), 2);
357 let x = Vector::new(space_xy, vec![Rational::from(1), Rational::from(2)]);
358 let y = Vector::new(space_xy, vec![Rational::from(6), Rational::from(3)]);
359 let z = Vector::new(space_xy, vec![Rational::from(7), Rational::from(5)]);
360 let w = Vector::new(space_xy, vec![Rational::from(-2), Rational::from(-4)]);
361
362 assert_eq!(c, &a + &b);
363 assert_eq!(z, &x + &y);
364 assert_eq!(a, a);
365 assert_ne!(a, b);
366 assert_ne!(a, x); assert_ne!(x.scalar_mul(&Rational::from(-2)), z);
368 assert_eq!(x.scalar_mul(&Rational::from(-2)), w);
369 }
370}