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