algebraeon_geometry/
coordinates.rs

1use algebraeon_rings::linear::matrix::Matrix;
2use std::borrow::Borrow;
3use std::hash::Hash;
4
5use super::*;
6
7#[derive(Clone)]
8pub struct Vector<FS: OrderedRingStructure + FieldStructure, SP: Borrow<AffineSpace<FS>>> {
9    ambient_space: SP,
10    coordinates: Vec<FS::Set>, //length equal to ambient_space.dimension()
11}
12
13impl<FS: OrderedRingStructure + FieldStructure, SP: Borrow<AffineSpace<FS>>> std::fmt::Debug
14    for Vector<FS, SP>
15{
16    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
17        f.debug_struct("Vector")
18            .field("coordinates", &self.coordinates)
19            .finish()
20    }
21}
22
23impl<FS: OrderedRingStructure + FieldStructure, SP: Borrow<AffineSpace<FS>>> PartialEq
24    for Vector<FS, SP>
25{
26    fn eq(&self, other: &Self) -> bool {
27        match common_space(self.ambient_space.borrow(), other.ambient_space.borrow()) {
28            Some(space) => {
29                let n = space.linear_dimension().unwrap();
30                (0..n).all(|i| {
31                    space
32                        .ordered_field()
33                        .equal(self.coordinate(i), other.coordinate(i))
34                })
35            }
36            None => false,
37        }
38    }
39}
40
41impl<FS: OrderedRingStructure + FieldStructure, SP: Borrow<AffineSpace<FS>>> Eq for Vector<FS, SP> {}
42
43impl<FS: OrderedRingStructure + FieldStructure, SP: Borrow<AffineSpace<FS>>> Hash for Vector<FS, SP>
44where
45    FS::Set: Hash,
46{
47    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
48        // self.ambient_space.borrow().hash(state);
49        self.coordinates.hash(state);
50    }
51}
52
53impl<FS: OrderedRingStructure + FieldStructure, SP: Borrow<AffineSpace<FS>>> Vector<FS, SP> {
54    pub fn new(ambient_space: SP, coordinates: Vec<FS::Set>) -> Self {
55        assert_eq!(
56            ambient_space.borrow().linear_dimension().unwrap(),
57            coordinates.len()
58        );
59        Self {
60            ambient_space,
61            coordinates,
62        }
63    }
64
65    pub fn construct(ambient_space: SP, mut coordinate_func: impl FnMut(usize) -> FS::Set) -> Self {
66        let coordinates = (0..ambient_space.borrow().linear_dimension().unwrap())
67            .map(|i| coordinate_func(i))
68            .collect();
69        Self {
70            ambient_space,
71            coordinates,
72        }
73    }
74
75    pub fn zero(ambient_space: SP) -> Self {
76        let ordered_field = ambient_space.borrow().ordered_field();
77        Self::construct(ambient_space, |_i| ordered_field.zero())
78    }
79
80    pub fn ambient_space(&self) -> &SP {
81        &self.ambient_space
82    }
83
84    // pub fn ordered_field(&self) -> Rc<FS> {
85    //     self.ambient_space.borrow().ordered_field()
86    // }
87
88    // pub fn dimension(&self) -> usize {
89    //     self.ambient_space.borrow().dimension()
90    // }
91
92    pub fn coordinate(&self, i: usize) -> &FS::Set {
93        self.coordinates.get(i).unwrap()
94    }
95
96    pub fn coordinate_mut(&mut self, i: usize) -> &mut FS::Set {
97        self.coordinates.get_mut(i).unwrap()
98    }
99
100    pub fn into_row(&self) -> Matrix<FS::Set> {
101        Matrix::construct(
102            1,
103            self.ambient_space().borrow().linear_dimension().unwrap(),
104            |_r, c| self.coordinate(c).clone(),
105        )
106    }
107
108    pub fn into_col(&self) -> Matrix<FS::Set> {
109        Matrix::construct(
110            self.ambient_space().borrow().linear_dimension().unwrap(),
111            1,
112            |r, _c| self.coordinate(r).clone(),
113        )
114    }
115}
116
117// -&vector
118impl<FS: OrderedRingStructure + FieldStructure, SP: Borrow<AffineSpace<FS>> + Clone> std::ops::Neg
119    for &Vector<FS, SP>
120{
121    type Output = Vector<FS, SP>;
122
123    fn neg(self) -> Self::Output {
124        Vector {
125            ambient_space: self.ambient_space.clone(),
126            coordinates: self
127                .coordinates
128                .iter()
129                .map(|x| self.ambient_space().borrow().ordered_field().neg(x))
130                .collect(),
131        }
132    }
133}
134
135// &vector + &vector
136impl<FS: OrderedRingStructure + FieldStructure, SP: Borrow<AffineSpace<FS>> + Clone>
137    std::ops::Add<&Vector<FS, SP>> for &Vector<FS, SP>
138{
139    type Output = Vector<FS, SP>;
140
141    fn add(self, other: &Vector<FS, SP>) -> Self::Output {
142        match common_space(self.ambient_space.clone(), other.ambient_space.clone()) {
143            Some(space) => {
144                let n = space.borrow().linear_dimension().unwrap();
145                let coordinates = (0..n)
146                    .map(|i| {
147                        space
148                            .borrow()
149                            .ordered_field()
150                            .add(self.coordinate(i), other.coordinate(i))
151                    })
152                    .collect();
153                Vector {
154                    ambient_space: space,
155                    coordinates,
156                }
157            }
158            None => panic!("Can't add vectors belonging to different spaces"),
159        }
160    }
161}
162
163// mut vector += &vector
164impl<FS: OrderedRingStructure + FieldStructure, SP: Borrow<AffineSpace<FS>> + Clone>
165    std::ops::AddAssign<&Vector<FS, SP>> for Vector<FS, SP>
166{
167    fn add_assign(&mut self, other: &Vector<FS, SP>) {
168        match common_space(self.ambient_space.clone(), other.ambient_space.clone()) {
169            Some(space) => {
170                let n = space.borrow().linear_dimension().unwrap();
171                for i in 0..n {
172                    space
173                        .borrow()
174                        .ordered_field()
175                        .add_mut(self.coordinate_mut(i), other.coordinate(i));
176                }
177            }
178            None => panic!("Can't add vectors belonging to different spaces"),
179        }
180    }
181}
182
183// &vector - &vector
184impl<FS: OrderedRingStructure + FieldStructure, SP: Borrow<AffineSpace<FS>> + Clone>
185    std::ops::Sub<&Vector<FS, SP>> for &Vector<FS, SP>
186{
187    type Output = Vector<FS, SP>;
188
189    fn sub(self, other: &Vector<FS, SP>) -> Self::Output {
190        self + &(-other)
191    }
192}
193
194// &vector * &scalar
195impl<FS: OrderedRingStructure + FieldStructure, SP: Borrow<AffineSpace<FS>> + Clone>
196    Vector<FS, SP>
197{
198    pub fn scalar_mul(&self, other: &FS::Set) -> Vector<FS, SP> {
199        Vector {
200            ambient_space: self.ambient_space.clone(),
201            coordinates: self
202                .coordinates
203                .iter()
204                .map(|x| self.ambient_space().borrow().ordered_field().mul(x, other))
205                .collect(),
206        }
207    }
208}
209
210#[cfg(test)]
211mod tests {
212    use algebraeon_nzq::rational::*;
213    use algebraeon_sets::structure::*;
214
215    use super::*;
216
217    #[test]
218    fn vector_from_mat() {
219        let space = AffineSpace::new_linear(Rational::structure(), 2);
220        let mat = Matrix::<Rational>::from_rows(vec![
221            vec![Rational::from(1), Rational::from(2)],
222            vec![Rational::from(3), Rational::from(4)],
223        ]);
224
225        mat.pprint();
226
227        let mut vecs = vectors_from_rows(&space, &mat);
228        let v2 = vecs.pop().unwrap();
229        let v1 = vecs.pop().unwrap();
230        println!("v1 = {:?}", v1);
231        println!("v2 = {:?}", v2);
232
233        assert_eq!(
234            v1,
235            Vector::new(&space, vec![Rational::from(1), Rational::from(2)])
236        );
237        assert_eq!(
238            v2,
239            Vector::new(&space, vec![Rational::from(3), Rational::from(4)])
240        );
241    }
242
243    #[test]
244    fn det() {
245        let space = AffineSpace::new_linear(Rational::structure(), 2);
246        let v1 = Vector::new(&space, vec![Rational::from(3), Rational::from(2)]);
247        let v2 = Vector::new(&space, vec![Rational::from(5), Rational::from(7)]);
248        assert_eq!(space.determinant(vec![&v1, &v2]), Rational::from(11));
249    }
250
251    #[test]
252    fn test_abgroup() {
253        let space_ab = AffineSpace::new_linear(Rational::structure(), 2);
254        let a = Vector::new(&space_ab, vec![Rational::from(1), Rational::from(2)]);
255        let b = Vector::new(&space_ab, vec![Rational::from(6), Rational::from(3)]);
256        let c = Vector::new(&space_ab, vec![Rational::from(7), Rational::from(5)]);
257
258        let space_xy = AffineSpace::new_linear(Rational::structure(), 2);
259        let x = Vector::new(&space_xy, vec![Rational::from(1), Rational::from(2)]);
260        let y = Vector::new(&space_xy, vec![Rational::from(6), Rational::from(3)]);
261        let z = Vector::new(&space_xy, vec![Rational::from(7), Rational::from(5)]);
262        let w = Vector::new(&space_xy, vec![Rational::from(-2), Rational::from(-4)]);
263
264        assert_eq!(c, &a + &b);
265        assert_eq!(z, &x + &y);
266        assert_eq!(a, a);
267        assert_ne!(a, b);
268        assert_ne!(a, x); //same coordinates but different space
269        assert_ne!(x.scalar_mul(&Rational::from(-2)), z);
270        assert_eq!(x.scalar_mul(&Rational::from(-2)), w);
271    }
272}