Skip to main content

ginger/
matrix2.rs

1// #![no_std]
2use core::ops::{Add, Div, Mul, Neg, Rem, Sub};
3use num_traits::{Num, Zero};
4
5// mod vector2;
6use super::Vector2;
7
8/// The code defines a generic struct called Matrix2 with two fields, x_ and y_, which are both of type
9/// Vector2.
10///
11/// Properties:
12///
13/// * `x_`: The `x_` property represents the first row of the `Matrix2` object. It is of type
14///   `Vector2<T>`, where `T` is a generic type parameter. This means that the elements of the first row
15///   are stored in a `Vector2` object.
16/// * `y_`: The `y_` property is a public field of type `Vector2<T>`. It represents the second row of
17///   the `Matrix2` object.
18#[cfg_attr(feature = "doc-images", doc = svgbobdoc::transform!(
19/// ```svgbob
20///  .──────┬──────.
21///  │ a_11 │ a_12 │
22///  ├──────┼──────┤
23///  │ a_21 │ a_22 │
24///  '──────┴──────'
25/// ```
26))]
27#[derive(PartialEq, Eq, Copy, Clone, Hash, Debug, Default)]
28// #[repr(C)]
29pub struct Matrix2<T> {
30    /// The first row of the Matrix2 object
31    pub x_: Vector2<T>,
32    /// The second row of the Matrix2 object
33    pub y_: Vector2<T>,
34}
35
36impl<T> Matrix2<T> {
37    /// Creates a new [`Matrix2<T>`].
38    ///
39    /// The `new` function creates a new [`Matrix2`] object with the given [`Vector2`] objects.
40    ///
41    /// Arguments:
42    ///
43    /// * `x_`: A vector representing the first row of the matrix.
44    /// * `y_`: The parameter `y_` is a `Vector2<T>` object representing the second row of the matrix.
45    ///
46    /// Returns:
47    ///
48    /// The `new` function returns a `Matrix2<T>` object.
49    ///
50    /// # Examples
51    ///
52    /// ```
53    /// use ginger::matrix2::Matrix2;
54    /// use ginger::vector2::Vector2;
55    ///
56    /// let x = Vector2::new(3, 4);
57    /// let y = Vector2::new(5, 6);
58    /// assert_eq!(Matrix2::new(x, y), Matrix2 { x_: x, y_: y });
59    /// ```
60    #[inline]
61    pub const fn new(x_: Vector2<T>, y_: Vector2<T>) -> Self {
62        Matrix2 { x_, y_ }
63    }
64}
65
66impl<T: Clone + Num> Matrix2<T> {
67    /// Calculate the determinant of this [`Matrix2<T>`].
68    ///
69    /// $$ \det(\mathbf{M}) = \mathbf{x} \times \mathbf{y} = x_1 y_2 - x_2 y_1 $$
70    ///
71    /// The `det` function calculates the determinant of a 2x2 matrix.
72    ///
73    /// Returns:
74    ///
75    /// The `det()` function returns the determinant of the `Matrix2<T>`.
76    ///
77    /// # Examples
78    ///
79    /// ```
80    /// use ginger::matrix2::Matrix2;
81    /// use ginger::vector2::Vector2;
82    ///
83    /// let x = Vector2::new(3, 4);
84    /// let y = Vector2::new(5, 6);
85    /// let matrix2 = Matrix2::new(x, y);
86    /// assert_eq!(matrix2.det(), -2);
87    /// ```
88    #[inline]
89    pub fn det(&self) -> T {
90        self.x_.cross(&self.y_)
91    }
92
93    /// Matrix-vector multiplication
94    ///
95    /// $$ \mathbf{M} \cdot \mathbf{v} = \begin{bmatrix} \mathbf{x} \cdot \mathbf{v} \\ \mathbf{y} \cdot \mathbf{v} \end{bmatrix} $$
96    ///
97    /// The `mdot` function performs matrix-vector multiplication.
98    ///
99    /// Arguments:
100    ///
101    /// * `v`: The parameter `v` is a reference to a `Vector2<T>` object, where `T` is the type of the
102    ///   elements in the vector.
103    ///
104    /// Returns:
105    ///
106    /// The `mdot` function returns a `Vector2<T>` object.
107    ///
108    /// # Examples
109    ///
110    /// ```
111    /// use ginger::matrix2::Matrix2;
112    /// use ginger::vector2::Vector2;
113    ///
114    /// let x = Vector2::new(3, 4);
115    /// let y = Vector2::new(5, 6);
116    /// let v = &Vector2::new(1, 1);
117    /// let matrix2 = Matrix2::new(x, y);
118    /// assert_eq!(matrix2.mdot(v), Vector2::new(7, 11));
119    /// ```
120    #[inline]
121    pub fn mdot(&self, v: &Vector2<T>) -> Vector2<T> {
122        Vector2::<T>::new(self.x_.dot(v), self.y_.dot(v))
123    }
124
125    /// The `scale` function multiplies a matrix by a scalar.
126    ///
127    /// $$\mathbf{M}' = \mathbf{M} \times \alpha = \begin{bmatrix} \alpha \mathbf{x} \\ \alpha \mathbf{y} \end{bmatrix}$$
128    ///
129    /// Arguments:
130    ///
131    /// * `alpha`: The parameter `alpha` represents the scalar value by which the matrix is multiplied.
132    ///
133    /// Returns:
134    ///
135    /// The `scale` method returns a new `Matrix2` object.
136    ///
137    /// # Examples
138    ///
139    /// ```
140    /// use ginger::matrix2::Matrix2;
141    /// use ginger::vector2::Vector2;
142    ///
143    /// let x = Vector2::new(3, 4);
144    /// let y = Vector2::new(5, 6);
145    /// let matrix2 = Matrix2::new(x, y);
146    /// assert_eq!(matrix2.scale(10), Matrix2 { x_: Vector2::new(30, 40), y_: Vector2::new(50, 60)});
147    /// ```
148    #[inline]
149    pub fn scale(&self, alpha: T) -> Self {
150        Self::new(self.x_.clone() * alpha.clone(), self.y_.clone() * alpha)
151    }
152
153    /// The `unscale` function divides each element of a matrix by a scalar value.
154    ///
155    /// $$\mathbf{M}' = \mathbf{M} / \alpha = \begin{bmatrix} \mathbf{x} / \alpha \\ \mathbf{y} / \alpha \end{bmatrix}$$
156    ///
157    /// Arguments:
158    ///
159    /// * `alpha`: The parameter `alpha` is a scalar value that is used to divide each element of the matrix
160    ///   by. It is used to scale down the matrix by dividing each element by `alpha`.
161    ///
162    /// Returns:
163    ///
164    /// The `unscale` method returns a new instance of `Matrix2` with the elements of `self` divided by the
165    /// scalar `alpha`.
166    ///
167    /// # Examples
168    ///
169    /// ```
170    /// use ginger::matrix2::Matrix2;
171    /// use ginger::vector2::Vector2;
172    ///
173    /// let x = Vector2::new(30, 40);
174    /// let y = Vector2::new(50, 60);
175    /// let matrix2 = Matrix2::new(x, y);
176    /// assert_eq!(matrix2.unscale(10), Matrix2 { x_: Vector2::new(3, 4), y_: Vector2::new(5, 6)});
177    /// ```
178    #[inline]
179    pub fn unscale(&self, alpha: T) -> Self {
180        Self::new(self.x_.clone() / alpha.clone(), self.y_.clone() / alpha)
181    }
182}
183
184macro_rules! forward_xf_xf_binop {
185    (impl $imp:ident, $method:ident) => {
186        impl<'a, 'b, T: Clone + Num> $imp<&'b Matrix2<T>> for &'a Matrix2<T> {
187            type Output = Matrix2<T>;
188
189            #[inline]
190            fn $method(self, other: &Matrix2<T>) -> Self::Output {
191                self.clone().$method(other.clone())
192            }
193        }
194    };
195}
196
197macro_rules! forward_xf_val_binop {
198    (impl $imp:ident, $method:ident) => {
199        impl<'a, T: Clone + Num> $imp<Matrix2<T>> for &'a Matrix2<T> {
200            type Output = Matrix2<T>;
201
202            #[inline]
203            fn $method(self, other: Matrix2<T>) -> Self::Output {
204                self.clone().$method(other)
205            }
206        }
207    };
208}
209
210macro_rules! forward_val_xf_binop {
211    (impl $imp:ident, $method:ident) => {
212        impl<'a, T: Clone + Num> $imp<&'a Matrix2<T>> for Matrix2<T> {
213            type Output = Matrix2<T>;
214
215            #[inline]
216            fn $method(self, other: &Matrix2<T>) -> Self::Output {
217                self.$method(other.clone())
218            }
219        }
220    };
221}
222
223macro_rules! forward_all_binop {
224    (impl $imp:ident, $method:ident) => {
225        forward_xf_xf_binop!(impl $imp, $method);
226        forward_xf_val_binop!(impl $imp, $method);
227        forward_val_xf_binop!(impl $imp, $method);
228    };
229}
230
231// arithmetic
232forward_all_binop!(impl Add, add);
233
234/// Matrix addition.
235///
236/// $$ \mathbf{A} + \mathbf{B} = (\mathbf{a}_x + \mathbf{b}_x,\; \mathbf{a}_y + \mathbf{b}_y) $$
237impl<T: Clone + Num> Add<Matrix2<T>> for Matrix2<T> {
238    type Output = Self;
239
240    #[inline]
241    fn add(self, other: Self) -> Self::Output {
242        Self::Output::new(self.x_ + other.x_, self.y_ + other.y_)
243    }
244}
245
246forward_all_binop!(impl Sub, sub);
247
248/// Matrix subtraction.
249///
250/// $$ \mathbf{A} - \mathbf{B} = (\mathbf{a}_x - \mathbf{b}_x,\; \mathbf{a}_y - \mathbf{b}_y) $$
251impl<T: Clone + Num> Sub<Matrix2<T>> for Matrix2<T> {
252    type Output = Self;
253
254    #[inline]
255    fn sub(self, other: Self) -> Self::Output {
256        Self::Output::new(self.x_ - other.x_, self.y_ - other.y_)
257    }
258}
259
260// Op Assign
261
262mod opassign {
263    use core::ops::{AddAssign, DivAssign, MulAssign, SubAssign};
264
265    use num_traits::NumAssign;
266
267    use crate::Matrix2;
268
269    impl<T: Clone + NumAssign> AddAssign for Matrix2<T> {
270        fn add_assign(&mut self, other: Self) {
271            self.x_ += other.x_;
272            self.y_ += other.y_;
273        }
274    }
275
276    impl<T: Clone + NumAssign> SubAssign for Matrix2<T> {
277        fn sub_assign(&mut self, other: Self) {
278            self.x_ -= other.x_;
279            self.y_ -= other.y_;
280        }
281    }
282
283    impl<T: Clone + NumAssign> MulAssign<T> for Matrix2<T> {
284        fn mul_assign(&mut self, other: T) {
285            self.x_ *= other.clone();
286            self.y_ *= other;
287        }
288    }
289
290    impl<T: Clone + NumAssign> DivAssign<T> for Matrix2<T> {
291        fn div_assign(&mut self, other: T) {
292            self.x_ /= other.clone();
293            self.y_ /= other;
294        }
295    }
296
297    macro_rules! forward_op_assign1 {
298        (impl $imp:ident, $method:ident) => {
299            impl<'a, T: Clone + NumAssign> $imp<&'a Matrix2<T>> for Matrix2<T> {
300                #[inline]
301                fn $method(&mut self, other: &Self) {
302                    self.$method(other.clone())
303                }
304            }
305        };
306    }
307
308    macro_rules! forward_op_assign2 {
309        (impl $imp:ident, $method:ident) => {
310            impl<'a, T: Clone + NumAssign> $imp<&'a T> for Matrix2<T> {
311                #[inline]
312                fn $method(&mut self, other: &T) {
313                    self.$method(other.clone())
314                }
315            }
316        };
317    }
318
319    forward_op_assign1!(impl AddAssign, add_assign);
320    forward_op_assign1!(impl SubAssign, sub_assign);
321    forward_op_assign2!(impl MulAssign, mul_assign);
322    forward_op_assign2!(impl DivAssign, div_assign);
323}
324
325/// Matrix negation.
326///
327/// $$ -\mathbf{M} = (-\mathbf{x},\; -\mathbf{y}) $$
328impl<T: Clone + Num + Neg<Output = T>> Neg for Matrix2<T> {
329    type Output = Self;
330
331    #[inline]
332    fn neg(self) -> Self::Output {
333        Self::Output::new(-self.x_, -self.y_)
334    }
335}
336
337/// Matrix negation (by reference).
338///
339/// $$ -\mathbf{M} = (-\mathbf{x},\; -\mathbf{y}) $$
340impl<T: Clone + Num + Neg<Output = T>> Neg for &Matrix2<T> {
341    type Output = Matrix2<T>;
342
343    #[inline]
344    fn neg(self) -> Self::Output {
345        -self.clone()
346    }
347}
348
349macro_rules! scalar_arithmetic {
350    (@forward $imp:ident::$method:ident for $($scalar:ident),*) => (
351        impl<'a, T: Clone + Num> $imp<&'a T> for Matrix2<T> {
352            type Output = Matrix2<T>;
353
354            #[inline]
355            fn $method(self, other: &T) -> Self::Output {
356                self.$method(other.clone())
357            }
358        }
359        impl<'a, T: Clone + Num> $imp<T> for &'a Matrix2<T> {
360            type Output = Matrix2<T>;
361
362            #[inline]
363            fn $method(self, other: T) -> Self::Output {
364                self.clone().$method(other)
365            }
366        }
367        impl<'a, 'b, T: Clone + Num> $imp<&'a T> for &'b Matrix2<T> {
368            type Output = Matrix2<T>;
369
370            #[inline]
371            fn $method(self, other: &T) -> Self::Output {
372                self.clone().$method(other.clone())
373            }
374        }
375        $(
376            impl<'a> $imp<&'a Matrix2<$scalar>> for $scalar {
377                type Output = Matrix2<$scalar>;
378
379                #[inline]
380                fn $method(self, other: &Matrix2<$scalar>) -> Matrix2<$scalar> {
381                    self.$method(other.clone())
382                }
383            }
384            impl<'a> $imp<Matrix2<$scalar>> for &'a $scalar {
385                type Output = Matrix2<$scalar>;
386
387                #[inline]
388                fn $method(self, other: Matrix2<$scalar>) -> Matrix2<$scalar> {
389                    self.clone().$method(other)
390                }
391            }
392            impl<'a, 'b> $imp<&'a Matrix2<$scalar>> for &'b $scalar {
393                type Output = Matrix2<$scalar>;
394
395                #[inline]
396                fn $method(self, other: &Matrix2<$scalar>) -> Matrix2<$scalar> {
397                    self.clone().$method(other.clone())
398                }
399            }
400        )*
401    );
402    ($($scalar:ident),*) => (
403        scalar_arithmetic!(@forward Mul::mul for $($scalar),*);
404        // scalar_arithmetic!(@forward Div::div for $($scalar),*);
405        // scalar_arithmetic!(@forward Rem::rem for $($scalar),*);
406
407        $(
408            impl Mul<Matrix2<$scalar>> for $scalar {
409                type Output = Matrix2<$scalar>;
410
411                #[inline]
412                fn mul(self, other: Matrix2<$scalar>) -> Self::Output {
413                    Self::Output::new(self * other.x_, self * other.y_)
414                }
415            }
416
417        )*
418    );
419}
420
421/// Scalar multiplication for matrices.
422///
423/// $$ \mathbf{M} \cdot s = (\mathbf{x} \cdot s,\; \mathbf{y} \cdot s) $$
424impl<T: Clone + Num> Mul<T> for Matrix2<T> {
425    type Output = Matrix2<T>;
426
427    #[inline]
428    fn mul(self, other: T) -> Self::Output {
429        Self::Output::new(self.x_ * other.clone(), self.y_ * other)
430    }
431}
432
433/// Scalar division for matrices.
434///
435/// $$ \mathbf{M} / s = (\mathbf{x} / s,\; \mathbf{y} / s) $$
436impl<T: Clone + Num> Div<T> for Matrix2<T> {
437    type Output = Self;
438
439    #[inline]
440    fn div(self, other: T) -> Self::Output {
441        Self::Output::new(self.x_ / other.clone(), self.y_ / other)
442    }
443}
444
445/// Scalar remainder for matrices.
446///
447/// $$ \mathbf{M} \bmod s = (\mathbf{x} \bmod s,\; \mathbf{y} \bmod s) $$
448impl<T: Clone + Num> Rem<T> for Matrix2<T> {
449    type Output = Matrix2<T>;
450
451    #[inline]
452    fn rem(self, other: T) -> Self::Output {
453        Self::Output::new(self.x_ % other.clone(), self.y_ % other)
454    }
455}
456
457scalar_arithmetic!(usize, u8, u16, u32, u64, u128, isize, i8, i16, i32, i64, i128, f32, f64);
458
459// constants
460impl<T: Clone + Num> Zero for Matrix2<T> {
461    /// The zero matrix.
462    ///
463    /// $$ \mathbf{0} = \begin{bmatrix} 0 & 0 \\ 0 & 0 \end{bmatrix} $$
464    #[inline]
465    fn zero() -> Self {
466        Self::new(Zero::zero(), Zero::zero())
467    }
468
469    /// Returns `true` if this matrix is the zero matrix.
470    ///
471    /// $$ \mathbf{M} = \mathbf{0} \iff \mathbf{x} = \mathbf{0} \land \mathbf{y} = \mathbf{0} $$
472    #[inline]
473    fn is_zero(&self) -> bool {
474        self.x_.is_zero() && self.y_.is_zero()
475    }
476
477    #[inline]
478    fn set_zero(&mut self) {
479        self.x_.set_zero();
480        self.y_.set_zero();
481    }
482}
483
484// #[cfg(test)]
485// fn hash<T: hash::Hash>(x: &T) -> u64 {
486//     use std::collections::hash_map::RandomState;
487//     use std::hash::{BuildHasher, Hasher};
488//     let mut hasher = <RandomState as BuildHasher>::Hasher::new();
489//     x.hash(&mut hasher);
490//     hasher.finish()
491// }
492
493#[cfg(test)]
494mod test {
495    #![allow(non_upper_case_globals)]
496
497    // use super::{hash, Matrix2, Vector2};
498    use super::{Matrix2, Vector2};
499    use core::f64;
500    use num_traits::Zero;
501
502    pub const _0_0v: Vector2<f64> = Vector2 { x_: 0.0, y_: 0.0 };
503    pub const _1_0v: Vector2<f64> = Vector2 { x_: 1.0, y_: 0.0 };
504    pub const _1_1v: Vector2<f64> = Vector2 { x_: 1.0, y_: 1.0 };
505    pub const _0_1v: Vector2<f64> = Vector2 { x_: 0.0, y_: 1.0 };
506    pub const _neg1_1v: Vector2<f64> = Vector2 { x_: -1.0, y_: 1.0 };
507    pub const _05_05v: Vector2<f64> = Vector2 { x_: 0.5, y_: 0.5 };
508    // pub const all_consts: [Vector2<f64>; 5] = [_0_0v, _1_0v, _1_1v, _neg1_1v, _05_05v];
509    pub const _4_2v: Vector2<f64> = Vector2 { x_: 4.0, y_: 2.0 };
510
511    pub const _0_0m: Matrix2<f64> = Matrix2 {
512        x_: _0_0v,
513        y_: _0_0v,
514    };
515    pub const _1_0m: Matrix2<f64> = Matrix2 {
516        x_: _1_0v,
517        y_: _0_0v,
518    };
519    pub const _1_1m: Matrix2<f64> = Matrix2 {
520        x_: _1_1v,
521        y_: _1_1v,
522    };
523    pub const _0_1m: Matrix2<f64> = Matrix2 {
524        x_: _0_0v,
525        y_: _1_0v,
526    };
527    pub const _neg1_1m: Matrix2<f64> = Matrix2 {
528        x_: _neg1_1v,
529        y_: _1_0v,
530    };
531    pub const _05_05m: Matrix2<f64> = Matrix2 {
532        x_: _05_05v,
533        y_: _05_05v,
534    };
535    pub const all_consts: [Matrix2<f64>; 5] = [_0_0m, _1_0m, _1_1m, _neg1_1m, _05_05m];
536    pub const _4_2m: Matrix2<f64> = Matrix2 {
537        x_: _4_2v,
538        y_: _4_2v,
539    };
540
541    #[test]
542    fn test_consts() {
543        // check our constants are what Matrix2::new creates
544        // fn test(c: Matrix2<f64>, r: f64, i: f64) {
545        //     assert_eq!(c, Matrix2::new(r, i));
546        // }
547        // test(_0_0v, 0.0, 0.0);
548        // test(_1_0v, 1.0, 0.0);
549        // test(_1_1v, 1.0, 1.0);
550        // test(_neg1_1v, -1.0, 1.0);
551        // test(_05_05v, 0.5, 0.5);
552
553        assert_eq!(_0_0m, Zero::zero());
554    }
555
556    #[test]
557    fn test_scale_unscale() {
558        assert_eq!(_05_05m.scale(2.0), _1_1m);
559        assert_eq!(_1_1m.unscale(2.0), _05_05m);
560        for &c in all_consts.iter() {
561            assert_eq!(c.scale(2.0).unscale(2.0), c);
562        }
563    }
564
565    // #[test]
566    // fn test_hash() {
567    //     let u = Vector2::new(0i32, 0i32);
568    //     let v = Vector2::new(1i32, 0i32);
569    //     let w = Vector2::new(0i32, 1i32);
570    //     let a = Matrix2::new(u, v);
571    //     let b = Matrix2::new(v, w);
572    //     let c = Matrix2::new(w, u);
573    //     assert!(hash(&a) != hash(&b));
574    //     assert!(hash(&b) != hash(&c));
575    //     assert!(hash(&c) != hash(&a));
576    // }
577
578    #[test]
579    fn test_new() {
580        let x = Vector2::new(1, 2);
581        let y = Vector2::new(3, 4);
582        let m = Matrix2::new(x, y);
583        assert_eq!(m.x_, x);
584        assert_eq!(m.y_, y);
585    }
586
587    #[test]
588    fn test_det() {
589        let m = Matrix2::new(Vector2::new(3, 4), Vector2::new(5, 6));
590        assert_eq!(m.det(), 3 * 6 - 4 * 5);
591
592        let m2 = Matrix2::new(Vector2::new(1.0, 2.0), Vector2::new(3.0, 4.0));
593        assert_eq!(m2.det(), -2.0);
594    }
595
596    #[test]
597    fn test_mdot() {
598        let m = Matrix2::new(Vector2::new(3, 4), Vector2::new(5, 6));
599        let v = Vector2::new(1, 1);
600        assert_eq!(m.mdot(&v), Vector2::new(7, 11));
601
602        let m2 = Matrix2::new(Vector2::new(1.0, 2.0), Vector2::new(3.0, 4.0));
603        let v2 = Vector2::new(2.0, 3.0);
604        assert_eq!(m2.mdot(&v2), Vector2::new(8.0, 18.0));
605    }
606
607    #[test]
608    fn test_scale() {
609        let m = Matrix2::new(Vector2::new(3, 4), Vector2::new(5, 6));
610        assert_eq!(
611            m.scale(2),
612            Matrix2::new(Vector2::new(6, 8), Vector2::new(10, 12))
613        );
614
615        let m2 = Matrix2::new(Vector2::new(1.5, 2.5), Vector2::new(3.5, 4.5));
616        assert_eq!(
617            m2.scale(2.0),
618            Matrix2::new(Vector2::new(3.0, 5.0), Vector2::new(7.0, 9.0))
619        );
620    }
621
622    #[test]
623    fn test_unscale() {
624        let m = Matrix2::new(Vector2::new(30, 40), Vector2::new(50, 60));
625        assert_eq!(
626            m.unscale(10),
627            Matrix2::new(Vector2::new(3, 4), Vector2::new(5, 6))
628        );
629
630        let m2 = Matrix2::new(Vector2::new(3.0, 5.0), Vector2::new(7.0, 9.0));
631        assert_eq!(
632            m2.unscale(2.0),
633            Matrix2::new(Vector2::new(1.5, 2.5), Vector2::new(3.5, 4.5))
634        );
635    }
636
637    #[test]
638    fn test_add() {
639        let m1 = Matrix2::new(Vector2::new(1, 2), Vector2::new(3, 4));
640        let m2 = Matrix2::new(Vector2::new(5, 6), Vector2::new(7, 8));
641        assert_eq!(
642            m1 + m2,
643            Matrix2::new(Vector2::new(6, 8), Vector2::new(10, 12))
644        );
645
646        let m3 = m1 + m2;
647        assert_eq!(m3, Matrix2::new(Vector2::new(6, 8), Vector2::new(10, 12)));
648
649        let m4 = m1 + m2;
650        assert_eq!(m4, Matrix2::new(Vector2::new(6, 8), Vector2::new(10, 12)));
651    }
652
653    #[test]
654    fn test_sub() {
655        let m1 = Matrix2::new(Vector2::new(5, 6), Vector2::new(7, 8));
656        let m2 = Matrix2::new(Vector2::new(1, 2), Vector2::new(3, 4));
657        assert_eq!(
658            m1 - m2,
659            Matrix2::new(Vector2::new(4, 4), Vector2::new(4, 4))
660        );
661
662        let m3 = m1 - m2;
663        assert_eq!(m3, Matrix2::new(Vector2::new(4, 4), Vector2::new(4, 4)));
664    }
665
666    #[test]
667    fn test_neg() {
668        let m = Matrix2::new(Vector2::new(1, -2), Vector2::new(-3, 4));
669        assert_eq!(-m, Matrix2::new(Vector2::new(-1, 2), Vector2::new(3, -4)));
670        assert_eq!(-&m, Matrix2::new(Vector2::new(-1, 2), Vector2::new(3, -4)));
671    }
672
673    #[test]
674    fn test_scalar_mul() {
675        let m = Matrix2::new(Vector2::new(2, 3), Vector2::new(4, 5));
676        assert_eq!(
677            m * 4,
678            Matrix2::new(Vector2::new(8, 12), Vector2::new(16, 20))
679        );
680        assert_eq!(
681            &m * 4,
682            Matrix2::new(Vector2::new(8, 12), Vector2::new(16, 20))
683        );
684        assert_eq!(
685            4 * m,
686            Matrix2::new(Vector2::new(8, 12), Vector2::new(16, 20))
687        );
688        assert_eq!(
689            4 * &m,
690            Matrix2::new(Vector2::new(8, 12), Vector2::new(16, 20))
691        );
692    }
693
694    #[test]
695    fn test_scalar_div() {
696        let m = Matrix2::new(Vector2::new(10, 20), Vector2::new(30, 40));
697        assert_eq!(m / 5, Matrix2::new(Vector2::new(2, 4), Vector2::new(6, 8)));
698    }
699
700    #[test]
701    fn test_scalar_rem() {
702        let m = Matrix2::new(Vector2::new(10, 21), Vector2::new(32, 43));
703        assert_eq!(m % 3, Matrix2::new(Vector2::new(1, 0), Vector2::new(2, 1)));
704    }
705
706    #[test]
707    fn test_zero() {
708        let zero = Matrix2::<i32>::zero();
709        assert_eq!(zero, Matrix2::new(Vector2::zero(), Vector2::zero()));
710        assert!(zero.is_zero());
711
712        let mut m = Matrix2::new(Vector2::new(1, 2), Vector2::new(3, 4));
713        assert!(!m.is_zero());
714        m.set_zero();
715        assert!(m.is_zero());
716    }
717
718    #[test]
719    fn test_add_assign() {
720        let mut m1 = Matrix2::new(Vector2::new(1, 2), Vector2::new(3, 4));
721        let m2 = Matrix2::new(Vector2::new(5, 6), Vector2::new(7, 8));
722        m1 += m2;
723        assert_eq!(m1, Matrix2::new(Vector2::new(6, 8), Vector2::new(10, 12)));
724
725        let mut m3 = Matrix2::new(Vector2::new(1, 2), Vector2::new(3, 4));
726        m3 += &m2;
727        assert_eq!(m3, Matrix2::new(Vector2::new(6, 8), Vector2::new(10, 12)));
728    }
729
730    #[test]
731    fn test_sub_assign() {
732        let mut m1 = Matrix2::new(Vector2::new(5, 6), Vector2::new(7, 8));
733        let m2 = Matrix2::new(Vector2::new(1, 2), Vector2::new(3, 4));
734        m1 -= m2;
735        assert_eq!(m1, Matrix2::new(Vector2::new(4, 4), Vector2::new(4, 4)));
736
737        let mut m3 = Matrix2::new(Vector2::new(5, 6), Vector2::new(7, 8));
738        m3 -= &m2;
739        assert_eq!(m3, Matrix2::new(Vector2::new(4, 4), Vector2::new(4, 4)));
740    }
741
742    #[test]
743    fn test_mul_assign() {
744        let mut m = Matrix2::new(Vector2::new(1, 2), Vector2::new(3, 4));
745        m *= 3;
746        assert_eq!(m, Matrix2::new(Vector2::new(3, 6), Vector2::new(9, 12)));
747
748        let mut m2 = Matrix2::new(Vector2::new(1, 2), Vector2::new(3, 4));
749        let scalar = 3;
750        m2 *= &scalar;
751        assert_eq!(m2, Matrix2::new(Vector2::new(3, 6), Vector2::new(9, 12)));
752    }
753
754    #[test]
755    fn test_div_assign() {
756        let mut m = Matrix2::new(Vector2::new(6, 9), Vector2::new(12, 15));
757        m /= 3;
758        assert_eq!(m, Matrix2::new(Vector2::new(2, 3), Vector2::new(4, 5)));
759
760        let mut m2 = Matrix2::new(Vector2::new(6, 9), Vector2::new(12, 15));
761        let scalar = 3;
762        m2 /= &scalar;
763        assert_eq!(m2, Matrix2::new(Vector2::new(2, 3), Vector2::new(4, 5)));
764    }
765
766    #[test]
767    fn test_float_operations() {
768        let m = Matrix2::new(Vector2::new(1.5, 2.5), Vector2::new(3.5, 4.5));
769        assert_eq!(
770            m.scale(2.0),
771            Matrix2::new(Vector2::new(3.0, 5.0), Vector2::new(7.0, 9.0))
772        );
773        assert_eq!(
774            m.unscale(0.5),
775            Matrix2::new(Vector2::new(3.0, 5.0), Vector2::new(7.0, 9.0))
776        );
777        assert_eq!(m.det(), 1.5 * 4.5 - 2.5 * 3.5);
778    }
779
780    #[test]
781    fn test_clone_and_eq() {
782        let m1 = Matrix2::new(Vector2::new(1, 2), Vector2::new(3, 4));
783        let m2 = m1;
784        assert_eq!(m1, m2);
785
786        let m3 = Matrix2::new(Vector2::new(2, 1), Vector2::new(4, 3));
787        assert_ne!(m1, m3);
788    }
789
790    #[test]
791    fn test_debug() {
792        let m = Matrix2::new(Vector2::new(1, 2), Vector2::new(3, 4));
793        assert_eq!(
794            format!("{:?}", m),
795            "Matrix2 { x_: Vector2 { x_: 1, y_: 2 }, y_: Vector2 { x_: 3, y_: 4 } }"
796        );
797    }
798
799    #[test]
800    fn test_forward_xf_val_binop() {
801        let m1 = Matrix2::new(Vector2::new(1, 2), Vector2::new(3, 4));
802        let m2 = Matrix2::new(Vector2::new(5, 6), Vector2::new(7, 8));
803        let result: Matrix2<i32> = m1 + m2;
804        assert_eq!(
805            result,
806            Matrix2::new(Vector2::new(6, 8), Vector2::new(10, 12))
807        );
808    }
809
810    #[test]
811    fn test_forward_val_xf_binop() {
812        let m1 = Matrix2::new(Vector2::new(1, 2), Vector2::new(3, 4));
813        let m2 = Matrix2::new(Vector2::new(5, 6), Vector2::new(7, 8));
814        let result: Matrix2<i32> = m1 + m2;
815        assert_eq!(
816            result,
817            Matrix2::new(Vector2::new(6, 8), Vector2::new(10, 12))
818        );
819    }
820
821    #[test]
822    fn test_scalar_arithmetic_forward() {
823        let m = Matrix2::new(Vector2::new(2, 3), Vector2::new(4, 5));
824        let scalar = 3;
825        let result: Matrix2<i32> = m * scalar;
826        assert_eq!(
827            result,
828            Matrix2::new(Vector2::new(6, 9), Vector2::new(12, 15))
829        );
830
831        let result2: Matrix2<i32> = m * scalar;
832        assert_eq!(
833            result2,
834            Matrix2::new(Vector2::new(6, 9), Vector2::new(12, 15))
835        );
836
837        let result3: Matrix2<i32> = 3 * &m;
838        assert_eq!(
839            result3,
840            Matrix2::new(Vector2::new(6, 9), Vector2::new(12, 15))
841        );
842    }
843
844    #[test]
845    fn test_scalar_left_mul() {
846        let m = Matrix2::new(Vector2::new(2, 3), Vector2::new(4, 5));
847        assert_eq!(
848            3 * m,
849            Matrix2::new(Vector2::new(6, 9), Vector2::new(12, 15))
850        );
851        assert_eq!(
852            3 * &m,
853            Matrix2::new(Vector2::new(6, 9), Vector2::new(12, 15))
854        );
855    }
856
857    #[test]
858    fn test_scalar_mul_by_ref_matrix() {
859        let m = Matrix2::new(Vector2::new(1, 2), Vector2::new(3, 4));
860        assert_eq!(
861            5 * &m,
862            Matrix2::new(Vector2::new(5, 10), Vector2::new(15, 20))
863        );
864    }
865}