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