oxygen_quark/matrix/
matrix2x2.rs

1#![allow(
2    clippy::erasing_op,
3    clippy::identity_op,
4    clippy::suspicious_op_assign_impl,
5    clippy::suspicious_arithmetic_impl
6)]
7
8use std::fmt;
9
10use super::{Matrix, MatrixError, TransformVector};
11use crate::fraction::Fraction;
12use crate::vector::{ VectorError, vector2d::Vector2D };
13
14pub struct Matrix2x2 {
15    /// The matrix data.
16    pub data: [Fraction; 2 * 2],
17}
18
19impl Matrix for Matrix2x2 {
20    type Data = Fraction;
21
22    /// Generates a new `Matrix2x2` with values `0`.
23    ///
24    fn new() -> Self {
25        Matrix2x2 {
26            data: [
27                Fraction::new_denom(0, 1),
28                Fraction::new_denom(0, 1),
29                Fraction::new_denom(0, 1),
30                Fraction::new_denom(0, 1),
31            ],
32        }
33    }
34
35    /// Generates a new `Matrix2x2` from the `Fraction` specified.
36    ///
37    fn from(value: Self::Data) -> Self {
38        Matrix2x2 {
39            data: [value, value, value, value],
40        }
41    }
42
43    /// Generates a new `Matrix2x2` from a list of `Fraction` values.
44    ///
45    fn from_slice(values: &[Self::Data]) -> Self {
46        let mut new_matrix = Matrix2x2::new();
47
48        new_matrix.data[0] = values[0];
49        new_matrix.data[1] = values[1];
50        new_matrix.data[2] = values[2];
51        new_matrix.data[3] = values[3];
52
53        new_matrix
54    }
55
56    /// Scales the given `Matrix2x2` by the given `Fraction`.
57    ///
58    fn scale(&self, scale: Self::Data) -> Self {
59        let mut scaled_matrix = Matrix2x2::new();
60
61        for i in 0..2 {
62            for j in 0..2 {
63                scaled_matrix.data[2 * i + j] = self.data[2 * i + j] * scale;
64            }
65        }
66
67        scaled_matrix
68    }
69
70    /// Calculates the determinant of the `Matrix2x2` and returns it, a `Fraction`.
71    ///
72    fn determinant(&self) -> Result<Self::Data, MatrixError> {
73        Ok(self.data[2 * 0 + 0] * self.data[2 * 1 + 1]
74            - self.data[2 * 0 + 1] * self.data[2 * 1 + 0])
75    }
76
77    /// Transposes the `Matrix2x2` and returns the result.
78    ///
79    fn transpose(&self) -> Self {
80        let mut transposed_matrix = Matrix2x2::new();
81
82        for i in 0..2 {
83            for j in 0..2 {
84                transposed_matrix.data[2 * i + j] = self.data[i + 2 * j];
85            }
86        }
87
88        transposed_matrix
89    }
90
91    /// Returns the cofactor of the `Matrix2x2`.
92    ///
93    fn cofactor(&self) -> Result<Self, MatrixError> {
94        let mut cofactor_matrix = Matrix2x2::new();
95
96        cofactor_matrix.data[2 * 0 + 0] = self.data[2 * 1 + 1];
97        cofactor_matrix.data[2 * 0 + 1] = -self.data[2 * 1 + 0];
98        cofactor_matrix.data[2 * 1 + 0] = -self.data[2 * 0 + 1];
99        cofactor_matrix.data[2 * 1 + 1] = self.data[2 * 0 + 0];
100
101        Ok(cofactor_matrix)
102    }
103
104    /// Returns the adjugate of the `Matrix2x2`.
105    /// Equal to calling cofactor() and then transpose().
106    ///
107    fn adjugate(&self) -> Result<Self, MatrixError> {
108        Ok(self.cofactor().unwrap().transpose())
109    }
110
111    /// Returns a `Result<Matrix2x2, ZeroDeterminantError>`.
112    /// It returns an `Result<Matrix2x2, ZeroDeterminantError>` because there won't always be an inverse (if the determinant is `0`), hence requires some extra checking.
113    ///
114    /// # Panics
115    /// Panics when trying to `unwrap()` a `None`-value.
116    ///
117    fn inverse(&self) -> Result<Self, MatrixError>
118    where
119        Self: Sized,
120    {
121        let determinant = self.determinant().unwrap();
122        if determinant == Self::Data::from(0_i16) {
123            return Err(MatrixError::ZeroDeterminantError);
124        }
125
126        let inverse_matrix = self.adjugate().unwrap();
127
128        Ok(inverse_matrix.scale(Self::Data::from(1_i16) / determinant))
129    }
130}
131
132impl TransformVector<Vector2D> for Matrix2x2 {
133    fn transform_vector(&self, other: Vector2D) -> Result<Vector2D, VectorError> {
134        Ok(crate::vector::vector2d::Vector2D {
135            data: [other[0] * self.data[2 * 0 + 0] + other[1] * self.data[2 * 0 + 1],
136            other[0] * self.data[2 * 1 + 0] + other[1] * self.data[2 * 1 + 1],]
137        })
138    }
139}
140
141impl std::cmp::PartialEq for Matrix2x2 {
142    fn eq(&self, other: &Matrix2x2) -> bool {
143        self.data.into_iter().eq(other.data.into_iter())
144    }
145}
146
147impl std::cmp::Eq for Matrix2x2 {}
148
149impl std::ops::Add for Matrix2x2 {
150    type Output = Matrix2x2;
151    fn add(self, other: Matrix2x2) -> Matrix2x2 {
152        let mut sum_matrix = Matrix2x2::new();
153
154        for i in 0..4 {
155            sum_matrix[i] = self.data[i] + other[i];
156        }
157
158        sum_matrix
159    }
160}
161
162impl std::ops::AddAssign for Matrix2x2 {
163    fn add_assign(&mut self, other: Matrix2x2) {
164        self.data[0] += other[0];
165        self.data[1] += other[1];
166        self.data[2] += other[2];
167        self.data[3] += other[3];
168    }
169}
170
171impl std::ops::Sub for Matrix2x2 {
172    type Output = Matrix2x2;
173    fn sub(self, other: Matrix2x2) -> Matrix2x2 {
174        let mut difference_matrix = Matrix2x2::new();
175
176        for i in 0..4 {
177            difference_matrix[i] = self.data[i] - other[i];
178        }
179
180        difference_matrix
181    }
182}
183
184impl std::ops::SubAssign for Matrix2x2 {
185    fn sub_assign(&mut self, other: Matrix2x2) {
186        self.data[0] -= other[0];
187        self.data[1] -= other[1];
188        self.data[2] -= other[2];
189        self.data[3] -= other[3];
190    }
191}
192
193impl std::ops::Mul for Matrix2x2 {
194    type Output = Matrix2x2;
195    fn mul(self, other: Matrix2x2) -> Matrix2x2 {
196        let mut product_matrix = Matrix2x2::new();
197
198        for i in 0..2 {
199            for j in 0..2 {
200                for m in 0..2 {
201                    product_matrix[2 * i + j] += self.data[2 * i + m] * other[2 * m + j];
202                }
203            }
204        }
205
206        product_matrix
207    }
208}
209
210impl std::ops::MulAssign for Matrix2x2 {
211    fn mul_assign(&mut self, other: Matrix2x2) {
212        let mut product_matrix = Matrix2x2::new();
213
214        for i in 0..2 {
215            for j in 0..2 {
216                for m in 0..2 {
217                    product_matrix[2 * i + j] += self.data[2 * i + m] * other[2 * m + j];
218                }
219            }
220        }
221
222        self.data[0..4].clone_from_slice(&product_matrix.data[0..4]);
223    }
224}
225
226impl std::ops::Neg for Matrix2x2 {
227    type Output = Matrix2x2;
228    fn neg(self) -> Matrix2x2 {
229        let mut negated_matrix = Matrix2x2::new();
230
231        negated_matrix[0] = -self.data[0];
232        negated_matrix[1] = -self.data[1];
233        negated_matrix[2] = -self.data[2];
234        negated_matrix[3] = -self.data[3];
235
236        negated_matrix
237    }
238}
239
240impl std::ops::Index<usize> for Matrix2x2 {
241    type Output = Fraction;
242    fn index(&self, index: usize) -> &Fraction {
243        &self.data[index]
244    }
245}
246
247impl std::ops::IndexMut<usize> for Matrix2x2 {
248    fn index_mut(&mut self, index: usize) -> &mut Fraction {
249        &mut self.data[index]
250    }
251}
252
253impl Copy for Matrix2x2 {}
254
255impl Clone for Matrix2x2 {
256    fn clone(&self) -> Matrix2x2 {
257        *self
258    }
259}
260
261impl fmt::Debug for Matrix2x2 {
262    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
263        write!(
264            f,
265            "\n[{}, {}]\n[{}, {}]",
266            self.data[2 * 0 + 0],
267            self.data[2 * 0 + 1],
268            self.data[2 * 1 + 0],
269            self.data[2 * 1 + 1]
270        )
271    }
272}
273
274impl fmt::Display for Matrix2x2 {
275    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
276        write!(
277            f,
278            "\n({}, {})\n({}, {})",
279            self.data[2 * 0 + 0],
280            self.data[2 * 0 + 1],
281            self.data[2 * 1 + 0],
282            self.data[2 * 1 + 1]
283        )
284    }
285}
286
287#[cfg(test)]
288mod tests {
289    use super::*;
290
291    #[test]
292    fn new_test() {
293        let values: [Fraction; 4] = [
294            Fraction::new_denom(0, 1),
295            Fraction::new_denom(0, 1),
296            Fraction::new_denom(0, 1),
297            Fraction::new_denom(0, 1),
298        ];
299
300        let matrix1: Matrix2x2 = Matrix2x2 {
301            data: [
302                Fraction::new_denom(0, 1),
303                Fraction::new_denom(0, 1),
304                Fraction::new_denom(0, 1),
305                Fraction::new_denom(0, 1),
306            ],
307        };
308
309        let matrix2 = Matrix2x2::new();
310        let matrix3 = Matrix::from(Fraction::new_denom(0, 1));
311        let matrix4 = Matrix2x2::from_slice(&values);
312
313        assert_eq!(matrix1, matrix2);
314        assert_eq!(matrix2, matrix3);
315        assert_eq!(matrix3, matrix4);
316    }
317
318    #[test]
319    fn addition_test() {
320        let matrix1: Matrix2x2 = Matrix::from(Fraction::new_denom(5, 1));
321        let matrix2 = Matrix::from(Fraction::new_denom(6, 1));
322
323        let result_matrix = Matrix::from(Fraction::new_denom(11, 1));
324
325        assert_eq!(matrix1 + matrix2, result_matrix);
326        assert_eq!(matrix2 + matrix1, result_matrix);
327    }
328
329    #[test]
330    fn subtraction_test() {
331        let matrix1: Matrix2x2 = Matrix::from(Fraction::new_denom(5, 1));
332        let matrix2 = Matrix::from(Fraction::new_denom(6, 1));
333
334        let result_matrix1 = Matrix::from(Fraction::new_denom(-1, 1));
335        let result_matrix2 = Matrix::from(Fraction::new_denom(1, 1));
336
337        assert_eq!(matrix1 - matrix2, result_matrix1);
338        assert_eq!(matrix2 - matrix1, result_matrix2);
339    }
340
341    #[test]
342    fn multiplication_test() {
343        let values1: [Fraction; 4] = [
344            Fraction::new_denom(4, 1),
345            Fraction::new_denom(2, 1),
346            Fraction::new_denom(5, 1),
347            Fraction::new_denom(1, 1),
348        ];
349
350        let values2: [Fraction; 4] = [
351            Fraction::new_denom(5, 1),
352            Fraction::new_denom(2, 1),
353            Fraction::new_denom(6, 1),
354            Fraction::new_denom(3, 1),
355        ];
356
357        let result_values1: [Fraction; 4] = [
358            Fraction::new_denom(32, 1),
359            Fraction::new_denom(14, 1),
360            Fraction::new_denom(31, 1),
361            Fraction::new_denom(13, 1),
362        ];
363
364        let result_values2: [Fraction; 4] = [
365            Fraction::new_denom(30, 1),
366            Fraction::new_denom(12, 1),
367            Fraction::new_denom(39, 1),
368            Fraction::new_denom(15, 1),
369        ];
370
371        let matrix1: Matrix2x2 = Matrix2x2::from_slice(&values1);
372        let matrix2 = Matrix2x2::from_slice(&values2);
373        let result_matrix1 = Matrix2x2::from_slice(&result_values1);
374        let result_matrix2 = Matrix2x2::from_slice(&result_values2);
375
376        assert_eq!(matrix1 * matrix2, result_matrix1);
377        assert_eq!(matrix2 * matrix1, result_matrix2);
378    }
379
380    #[test]
381    fn scale_test() {
382        let scale = Fraction::new_denom(5, 1);
383        let values: [Fraction; 4] = [
384            Fraction::new_denom(4, 1),
385            Fraction::new_denom(2, 1),
386            Fraction::new_denom(5, 1),
387            Fraction::new_denom(1, 1),
388        ];
389
390        let result_values: [Fraction; 4] = [
391            Fraction::new_denom(4 * 5, 1),
392            Fraction::new_denom(2 * 5, 1),
393            Fraction::new_denom(5 * 5, 1),
394            Fraction::new_denom(1 * 5, 1),
395        ];
396
397        let matrix = Matrix2x2::from_slice(&values);
398        let result_matrix = Matrix2x2::from_slice(&result_values);
399
400        assert_eq!(matrix.scale(scale), result_matrix);
401    }
402
403    #[test]
404    fn transpose_test() {
405        let values1: [Fraction; 4] = [
406            Fraction::new_denom(2, 1),
407            Fraction::new_denom(6, 1),
408            Fraction::new_denom(5, 1),
409            Fraction::new_denom(1, 1),
410        ];
411
412        let result_values: [Fraction; 4] = [
413            Fraction::new_denom(2, 1),
414            Fraction::new_denom(5, 1),
415            Fraction::new_denom(6, 1),
416            Fraction::new_denom(1, 1),
417        ];
418
419        let matrix = Matrix2x2::from_slice(&values1);
420        let result_matrix = Matrix2x2::from_slice(&result_values);
421
422        assert_eq!(matrix.transpose(), result_matrix);
423    }
424
425    #[test]
426    fn cofactor_test() {
427        let values: [Fraction; 4] = [
428            Fraction::new_denom(5, 1),
429            Fraction::new_denom(2, 1),
430            Fraction::new_denom(7, 1),
431            Fraction::new_denom(2, 1),
432        ];
433
434        let result_values: [Fraction; 4] = [
435            Fraction::new_denom(2, 1),
436            Fraction::new_denom(-7, 1),
437            Fraction::new_denom(-2, 1),
438            Fraction::new_denom(5, 1),
439        ];
440
441        let matrix = Matrix2x2::from_slice(&values);
442        let result_matrix = Matrix2x2::from_slice(&result_values);
443
444        assert_eq!(matrix.cofactor().unwrap(), result_matrix);
445    }
446
447    #[test]
448    fn adjugate_test() {
449        let values: [Fraction; 4] = [
450            Fraction::new_denom(5, 1),
451            Fraction::new_denom(2, 1),
452            Fraction::new_denom(7, 1),
453            Fraction::new_denom(2, 1),
454        ];
455
456        let result_values: [Fraction; 4] = [
457            Fraction::new_denom(2, 1),
458            Fraction::new_denom(-2, 1),
459            Fraction::new_denom(-7, 1),
460            Fraction::new_denom(5, 1),
461        ];
462
463        let matrix = Matrix2x2::from_slice(&values);
464        let result_matrix = Matrix2x2::from_slice(&result_values);;
465
466        assert_eq!(matrix.adjugate().unwrap(), result_matrix);
467    }
468
469    #[test]
470    fn determinant_test() {
471        let values: [Fraction; 4] = [
472            Fraction::new_denom(4, 1),
473            Fraction::new_denom(2, 1),
474            Fraction::new_denom(5, 1),
475            Fraction::new_denom(1, 1),
476        ];
477
478        let matrix = Matrix2x2::from_slice(&values);
479
480        let determinant = Fraction::new_denom(-6, 1);
481
482        assert_eq!(matrix.determinant().unwrap(), determinant);
483    }
484
485    #[test]
486    fn inverse_test() {
487        let values: [Fraction; 4] = [
488            Fraction::new_denom(5, 1),
489            Fraction::new_denom(2, 1),
490            Fraction::new_denom(4, 1),
491            Fraction::new_denom(7, 1),
492        ];
493
494        let result_values: [Fraction; 4] = [
495            Fraction::new_denom(7, 27),
496            Fraction::new_denom(-2, 27),
497            Fraction::new_denom(-4, 27),
498            Fraction::new_denom(5, 27),
499        ];
500
501        let matrix = Matrix2x2::from_slice(&values);
502        let result_matrix = Matrix2x2::from_slice(&result_values);
503
504        assert_eq!(matrix.inverse().unwrap(), result_matrix);
505    }
506}