Skip to main content

embedded_matrix/
lib.rs

1// Copyright (C) 2026 Jorge Andre Castro
2//
3// Ce programme est un logiciel libre : vous pouvez le redistribuer et/ou le modifier
4// selon les termes de la Licence Publique Générale GNU telle que publiée par la
5// Free Software Foundation, soit la version 2 de la licence, soit (à votre convention)
6// n'importe quelle version ultérieure.
7
8//! # embedded-matrix
9//!
10//! Matrices 2×2 et 3×3 en `f32` pour systèmes embarqués `no_std`.
11//!
12//! Sans dépendance, sans `unsafe`.
13//!
14//! ```rust
15//! use embedded_matrix::{Matrix2x2, Matrix3x3, MatrixError};
16//!
17//! // Identité 2×2
18//! let i2 = Matrix2x2::identity();
19//!
20//! // Produit matriciel avec l'opérateur *
21//! let a = Matrix3x3::new([
22//!     [1.0, 2.0, 3.0],
23//!     [4.0, 5.0, 6.0],
24//!     [7.0, 8.0, 9.0],
25//! ]);
26//! let b = Matrix3x3::identity();
27//! let c = a * b;  // == a, syntaxe opérateur
28//!
29//! // Addition et soustraction
30//! let d = a + b;
31//! let e = d - b;
32//!
33//! // Scalaire
34//! let f = a * 2.0;
35//!
36//! // Inversion (retourne Err si singulière)
37//! match Matrix2x2::identity().inv() {
38//!     Ok(inv) => { let _ = inv; }
39//!     Err(MatrixError::SingularMatrix) => { /* gérer */ }
40//! }
41//! ```
42
43#![no_std]
44#![forbid(unsafe_code)]
45#![warn(missing_docs)]
46//  Erreur
47/// Erreur retournée lors d'une opération invalide sur une matrice.
48#[derive(Debug, Clone, Copy, PartialEq, Eq)]
49pub enum MatrixError {
50    /// La matrice est singulière (déterminant nul) : inversion impossible.
51    SingularMatrix,
52}
53//  Matrix2x2
54/// Matrice 2×2 en `f32`, stockée en row-major.
55///
56/// ```
57/// use embedded_matrix::Matrix2x2;
58///
59/// let m = Matrix2x2::new([[1.0, 2.0], [3.0, 4.0]]);
60/// assert!((m.det() - (-2.0)).abs() < 1e-5);
61/// ```
62#[derive(Debug, Clone, Copy, PartialEq)]
63pub struct Matrix2x2 {
64    data: [[f32; 2]; 2],
65}
66
67impl Matrix2x2 {
68    //  Constructeurs 
69
70    /// Crée une matrice à partir d'un tableau row-major.
71    #[inline]
72    pub const fn new(data: [[f32; 2]; 2]) -> Self {
73        Self { data }
74    }
75
76    /// Matrice identité.
77    #[inline]
78    pub const fn identity() -> Self {
79        Self::new([[1.0, 0.0], [0.0, 1.0]])
80    }
81
82    /// Matrice nulle.
83    #[inline]
84    pub const fn zero() -> Self {
85        Self::new([[0.0, 0.0], [0.0, 0.0]])
86    }
87
88    // Accès 
89    /// Retourne l'élément à la ligne `row` et colonne `col` (0-indexé).
90    #[inline]
91    pub fn get(&self, row: usize, col: usize) -> f32 {
92        self.data[row][col]
93    }
94
95    /// Donne accès aux données brutes row-major.
96    #[inline]
97    pub fn as_array(&self) -> &[[f32; 2]; 2] {
98        &self.data
99    }
100
101    // Opérations arithmétiques
102    /// Addition terme à terme.
103    #[inline]
104    pub fn add(&self, rhs: &Self) -> Self {
105        Self::new([
106            [self.data[0][0] + rhs.data[0][0], self.data[0][1] + rhs.data[0][1]],
107            [self.data[1][0] + rhs.data[1][0], self.data[1][1] + rhs.data[1][1]],
108        ])
109    }
110
111    /// Soustraction terme à terme.
112    #[inline]
113    pub fn sub(&self, rhs: &Self) -> Self {
114        Self::new([
115            [self.data[0][0] - rhs.data[0][0], self.data[0][1] - rhs.data[0][1]],
116            [self.data[1][0] - rhs.data[1][0], self.data[1][1] - rhs.data[1][1]],
117        ])
118    }
119
120    /// Produit matriciel standard.
121    #[inline]
122    pub fn mul(&self, rhs: &Self) -> Self {
123        let a = &self.data;
124        let b = &rhs.data;
125        Self::new([
126            [
127                a[0][0] * b[0][0] + a[0][1] * b[1][0],
128                a[0][0] * b[0][1] + a[0][1] * b[1][1],
129            ],
130            [
131                a[1][0] * b[0][0] + a[1][1] * b[1][0],
132                a[1][0] * b[0][1] + a[1][1] * b[1][1],
133            ],
134        ])
135    }
136
137    /// Multiplication par un scalaire.
138    #[inline]
139    pub fn scale(&self, s: f32) -> Self {
140        Self::new([
141            [self.data[0][0] * s, self.data[0][1] * s],
142            [self.data[1][0] * s, self.data[1][1] * s],
143        ])
144    }
145
146    //  Propriétés 
147    /// Transposée.
148    #[inline]
149    pub fn transpose(&self) -> Self {
150        Self::new([
151            [self.data[0][0], self.data[1][0]],
152            [self.data[0][1], self.data[1][1]],
153        ])
154    }
155
156    /// Déterminant : `ad - bc`.
157    #[inline]
158    pub fn det(&self) -> f32 {
159        self.data[0][0] * self.data[1][1] - self.data[0][1] * self.data[1][0]
160    }
161
162    /// Trace (somme des éléments diagonaux).
163    #[inline]
164    pub fn trace(&self) -> f32 {
165        self.data[0][0] + self.data[1][1]
166    }
167
168    /// Inverse de la matrice.
169    ///
170    /// Retourne `Err(MatrixError::SingularMatrix)` si le déterminant est nul
171    /// (seuil : `|det| < 1e-7`).
172    pub fn inv(&self) -> Result<Self, MatrixError> {
173        let d = self.det();
174        if (if d < 0.0 { -d } else { d }) < 1e-7 {
175            return Err(MatrixError::SingularMatrix);
176        }
177        let inv_d = 1.0 / d;
178        Ok(Self::new([
179            [ self.data[1][1] * inv_d, -self.data[0][1] * inv_d],
180            [-self.data[1][0] * inv_d,  self.data[0][0] * inv_d],
181        ]))
182    }
183}
184
185// core::ops pour Matrix2x2 
186/// `a + b`  →  addition terme à terme.
187impl core::ops::Add for Matrix2x2 {
188    type Output = Self;
189    #[inline]
190    fn add(self, rhs: Self) -> Self {
191        Matrix2x2::add(&self, &rhs)
192    }
193}
194
195/// `a - b`  →  soustraction terme à terme.
196impl core::ops::Sub for Matrix2x2 {
197    type Output = Self;
198    #[inline]
199    fn sub(self, rhs: Self) -> Self {
200        Matrix2x2::sub(&self, &rhs)
201    }
202}
203
204/// `a * b`  →  produit matriciel.
205impl core::ops::Mul for Matrix2x2 {
206    type Output = Self;
207    #[inline]
208    fn mul(self, rhs: Self) -> Self {
209        Matrix2x2::mul(&self, &rhs)
210    }
211}
212
213/// `a * s`  →  multiplication par un scalaire `f32`.
214impl core::ops::Mul<f32> for Matrix2x2 {
215    type Output = Self;
216    #[inline]
217    fn mul(self, s: f32) -> Self {
218        self.scale(s)
219    }
220}
221
222/// `-a`  →  négation terme à terme.
223impl core::ops::Neg for Matrix2x2 {
224    type Output = Self;
225    #[inline]
226    fn neg(self) -> Self {
227        self.scale(-1.0)
228    }
229}
230
231
232//  Matrix3x3
233/// Matrice 3×3 en `f32`, stockée en row-major.
234///
235/// ```
236/// use embedded_matrix::Matrix3x3;
237///
238/// let m = Matrix3x3::identity();
239/// assert!((m.det() - 1.0).abs() < 1e-5);
240/// assert!((m.trace() - 3.0).abs() < 1e-5);
241/// ```
242#[derive(Debug, Clone, Copy, PartialEq)]
243pub struct Matrix3x3 {
244    data: [[f32; 3]; 3],
245}
246
247impl Matrix3x3 {
248    // Constructeurs 
249
250    /// Crée une matrice à partir d'un tableau row-major.
251    #[inline]
252    pub const fn new(data: [[f32; 3]; 3]) -> Self {
253        Self { data }
254    }
255
256    /// Matrice identité.
257    #[inline]
258    pub const fn identity() -> Self {
259        Self::new([
260            [1.0, 0.0, 0.0],
261            [0.0, 1.0, 0.0],
262            [0.0, 0.0, 1.0],
263        ])
264    }
265
266    /// Matrice nulle.
267    #[inline]
268    pub const fn zero() -> Self {
269        Self::new([[0.0; 3]; 3])
270    }
271
272    //  Accès 
273    /// Retourne l'élément à la ligne `row` et colonne `col` (0-indexé).
274    #[inline]
275    pub fn get(&self, row: usize, col: usize) -> f32 {
276        self.data[row][col]
277    }
278
279    /// Donne accès aux données brutes row-major.
280    #[inline]
281    pub fn as_array(&self) -> &[[f32; 3]; 3] {
282        &self.data
283    }
284
285    //  Opérations arithmétiques 
286    /// Additionne cette matrice avec une autre matrice terme à terme.
287    ///
288    /// # Arguments
289    ///
290    /// * `rhs`  La matrice à additionner (membre droit)
291    ///
292    /// # Retours
293    ///
294    /// Une nouvelle matrice contenant la somme terme à terme
295    #[inline]
296    pub fn add(&self, rhs: &Self) -> Self {
297        let mut out = [[0.0f32; 3]; 3];
298        for i in 0..3 {
299            for j in 0..3 {
300                out[i][j] = self.data[i][j] + rhs.data[i][j];
301            }
302        }
303        Self::new(out)
304    }
305
306    /// Soustraction terme à terme.
307    #[inline]
308    pub fn sub(&self, rhs: &Self) -> Self {
309        let mut out = [[0.0f32; 3]; 3];
310        for i in 0..3 {
311            for j in 0..3 {
312                out[i][j] = self.data[i][j] - rhs.data[i][j];
313            }
314        }
315        Self::new(out)
316    }
317
318    /// Produit matriciel standard.
319    #[inline]
320    pub fn mul(&self, rhs: &Self) -> Self {
321        let mut out = [[0.0f32; 3]; 3];
322        for i in 0..3 {
323            for j in 0..3 {
324                for k in 0..3 {
325                    out[i][j] += self.data[i][k] * rhs.data[k][j];
326                }
327            }
328        }
329        Self::new(out)
330    }
331
332    /// Multiplication par un scalaire.
333    #[inline]
334    pub fn scale(&self, s: f32) -> Self {
335        let mut out = [[0.0f32; 3]; 3];
336        for i in 0..3 {
337            for j in 0..3 {
338                out[i][j] = self.data[i][j] * s;
339            }
340        }
341        Self::new(out)
342    }
343
344    //  Propriétés 
345    /// Transposée.
346    #[inline]
347    pub fn transpose(&self) -> Self {
348        let mut out = [[0.0f32; 3]; 3];
349        for i in 0..3 {
350            for j in 0..3 {
351                out[j][i] = self.data[i][j];
352            }
353        }
354        Self::new(out)
355    }
356
357    /// Déterminant par la règle de Sarrus.
358    #[inline]
359    pub fn det(&self) -> f32 {
360        let d = &self.data;
361        d[0][0] * (d[1][1] * d[2][2] - d[1][2] * d[2][1])
362            - d[0][1] * (d[1][0] * d[2][2] - d[1][2] * d[2][0])
363            + d[0][2] * (d[1][0] * d[2][1] - d[1][1] * d[2][0])
364    }
365
366    /// Trace (somme des éléments diagonaux).
367    #[inline]
368    pub fn trace(&self) -> f32 {
369        self.data[0][0] + self.data[1][1] + self.data[2][2]
370    }
371
372    /// Inverse par la méthode des cofacteurs.
373    ///
374    /// Retourne `Err(MatrixError::SingularMatrix)` si `|det| < 1e-7`.
375    pub fn inv(&self) -> Result<Self, MatrixError> {
376        let det = self.det();
377        if (if det < 0.0 { -det } else { det }) < 1e-7 {
378            return Err(MatrixError::SingularMatrix);
379        }
380        let d = &self.data;
381        let inv_det = 1.0 / det;
382
383        // Matrice des cofacteurs transposée (= matrice adjointe)
384        Ok(Self::new([
385            [
386                (d[1][1] * d[2][2] - d[1][2] * d[2][1]) * inv_det,
387                (d[0][2] * d[2][1] - d[0][1] * d[2][2]) * inv_det,
388                (d[0][1] * d[1][2] - d[0][2] * d[1][1]) * inv_det,
389            ],
390            [
391                (d[1][2] * d[2][0] - d[1][0] * d[2][2]) * inv_det,
392                (d[0][0] * d[2][2] - d[0][2] * d[2][0]) * inv_det,
393                (d[0][2] * d[1][0] - d[0][0] * d[1][2]) * inv_det,
394            ],
395            [
396                (d[1][0] * d[2][1] - d[1][1] * d[2][0]) * inv_det,
397                (d[0][1] * d[2][0] - d[0][0] * d[2][1]) * inv_det,
398                (d[0][0] * d[1][1] - d[0][1] * d[1][0]) * inv_det,
399            ],
400        ]))
401    }
402}
403
404//  core::ops pour Matrix3x3 
405
406/// `a + b`  →  addition terme à terme.
407impl core::ops::Add for Matrix3x3 {
408    type Output = Self;
409    #[inline]
410    fn add(self, rhs: Self) -> Self {
411        Matrix3x3::add(&self, &rhs)
412    }
413}
414
415/// `a - b`  →  soustraction terme à terme.
416impl core::ops::Sub for Matrix3x3 {
417    type Output = Self;
418    #[inline]
419    fn sub(self, rhs: Self) -> Self {
420        Matrix3x3::sub(&self, &rhs)
421    }
422}
423
424/// `a * b`  →  produit matriciel.
425impl core::ops::Mul for Matrix3x3 {
426    type Output = Self;
427    #[inline]
428    fn mul(self, rhs: Self) -> Self {
429        Matrix3x3::mul(&self, &rhs)
430    }
431}
432
433/// `a * s`  →  multiplication par un scalaire `f32`.
434impl core::ops::Mul<f32> for Matrix3x3 {
435    type Output = Self;
436    #[inline]
437    fn mul(self, s: f32) -> Self {
438        self.scale(s)
439    }
440}
441
442/// `-a`  →  négation terme à terme.
443impl core::ops::Neg for Matrix3x3 {
444    type Output = Self;
445    #[inline]
446    fn neg(self) -> Self {
447        self.scale(-1.0)
448    }
449}
450
451
452//  Tests
453
454#[cfg(test)]
455mod tests {
456    use super::*;
457
458    //  Matrix2x2 
459    #[test]
460    fn m2_identity_det() {
461        assert!((Matrix2x2::identity().det() - 1.0).abs() < 1e-6);
462    }
463
464    #[test]
465    fn m2_det() {
466        let m = Matrix2x2::new([[1.0, 2.0], [3.0, 4.0]]);
467        assert!((m.det() - (-2.0)).abs() < 1e-6);
468    }
469
470    #[test]
471    fn m2_trace() {
472        let m = Matrix2x2::new([[1.0, 2.0], [3.0, 4.0]]);
473        assert!((m.trace() - 5.0).abs() < 1e-6);
474    }
475
476    #[test]
477    fn m2_add_sub() {
478        let a = Matrix2x2::new([[1.0, 2.0], [3.0, 4.0]]);
479        let b = Matrix2x2::new([[5.0, 6.0], [7.0, 8.0]]);
480        let s = a.add(&b);
481        assert!((s.get(0, 0) - 6.0).abs() < 1e-6);
482        assert!((s.get(1, 1) - 12.0).abs() < 1e-6);
483        let d = b.sub(&a);
484        assert!((d.get(0, 0) - 4.0).abs() < 1e-6);
485    }
486
487    #[test]
488    fn m2_mul_identity() {
489        let m = Matrix2x2::new([[3.0, 1.0], [2.0, 4.0]]);
490        let r = m.mul(&Matrix2x2::identity());
491        assert!((r.get(0, 0) - m.get(0, 0)).abs() < 1e-6);
492        assert!((r.get(1, 1) - m.get(1, 1)).abs() < 1e-6);
493    }
494
495    #[test]
496    fn m2_mul() {
497        let a = Matrix2x2::new([[1.0, 2.0], [3.0, 4.0]]);
498        let b = Matrix2x2::new([[2.0, 0.0], [1.0, 3.0]]);
499        let c = a.mul(&b);
500        // [1*2+2*1, 1*0+2*3] = [4, 6]
501        // [3*2+4*1, 3*0+4*3] = [10, 12]
502        assert!((c.get(0, 0) - 4.0).abs() < 1e-6);
503        assert!((c.get(0, 1) - 6.0).abs() < 1e-6);
504        assert!((c.get(1, 0) - 10.0).abs() < 1e-6);
505        assert!((c.get(1, 1) - 12.0).abs() < 1e-6);
506    }
507
508    #[test]
509    fn m2_scale() {
510        let m = Matrix2x2::new([[1.0, 2.0], [3.0, 4.0]]);
511        let s = m.scale(2.0);
512        assert!((s.get(0, 0) - 2.0).abs() < 1e-6);
513        assert!((s.get(1, 1) - 8.0).abs() < 1e-6);
514    }
515
516    #[test]
517    fn m2_transpose() {
518        let m = Matrix2x2::new([[1.0, 2.0], [3.0, 4.0]]);
519        let t = m.transpose();
520        assert!((t.get(0, 1) - 3.0).abs() < 1e-6);
521        assert!((t.get(1, 0) - 2.0).abs() < 1e-6);
522    }
523
524    #[test]
525    fn m2_inv_ok() {
526        let m = Matrix2x2::new([[1.0, 2.0], [3.0, 4.0]]);
527        let inv = m.inv().unwrap();
528        // M * M^-1 doit être proche de l'identité
529        let i = m.mul(&inv);
530        assert!((i.get(0, 0) - 1.0).abs() < 1e-5);
531        assert!((i.get(1, 1) - 1.0).abs() < 1e-5);
532        assert!(i.get(0, 1).abs() < 1e-5);
533        assert!(i.get(1, 0).abs() < 1e-5);
534    }
535
536    #[test]
537    fn m2_inv_singular() {
538        let m = Matrix2x2::new([[1.0, 2.0], [2.0, 4.0]]); // det = 0
539        assert_eq!(m.inv(), Err(MatrixError::SingularMatrix));
540    }
541
542    //  Matrix3x3 
543
544    #[test]
545    fn m3_identity_det() {
546        assert!((Matrix3x3::identity().det() - 1.0).abs() < 1e-6);
547    }
548
549    #[test]
550    fn m3_identity_trace() {
551        assert!((Matrix3x3::identity().trace() - 3.0).abs() < 1e-6);
552    }
553
554    #[test]
555    fn m3_det() {
556        let m = Matrix3x3::new([
557            [1.0, 2.0, 3.0],
558            [4.0, 5.0, 6.0],
559            [7.0, 8.0, 9.0],
560        ]);
561        // Matrice singulière, det = 0
562        assert!(m.det().abs() < 1e-4);
563    }
564
565    #[test]
566    fn m3_det_nonzero() {
567        let m = Matrix3x3::new([
568            [2.0, -1.0, 0.0],
569            [-1.0, 2.0, -1.0],
570            [0.0, -1.0, 2.0],
571        ]);
572        assert!((m.det() - 4.0).abs() < 1e-5);
573    }
574
575    #[test]
576    fn m3_add_sub() {
577        let a = Matrix3x3::identity();
578        let b = Matrix3x3::identity();
579        let s = a.add(&b);
580        assert!((s.get(0, 0) - 2.0).abs() < 1e-6);
581        let d = s.sub(&a);
582        assert!((d.get(0, 0) - 1.0).abs() < 1e-6);
583    }
584
585    #[test]
586    fn m3_mul_identity() {
587        let m = Matrix3x3::new([
588            [1.0, 2.0, 3.0],
589            [0.0, 1.0, 4.0],
590            [5.0, 6.0, 0.0],
591        ]);
592        let r = m.mul(&Matrix3x3::identity());
593        for i in 0..3 {
594            for j in 0..3 {
595                assert!((r.get(i, j) - m.get(i, j)).abs() < 1e-6);
596            }
597        }
598    }
599
600    #[test]
601    fn m3_transpose() {
602        let m = Matrix3x3::new([
603            [1.0, 2.0, 3.0],
604            [4.0, 5.0, 6.0],
605            [7.0, 8.0, 9.0],
606        ]);
607        let t = m.transpose();
608        assert!((t.get(0, 1) - 4.0).abs() < 1e-6);
609        assert!((t.get(1, 0) - 2.0).abs() < 1e-6);
610        assert!((t.get(2, 0) - 3.0).abs() < 1e-6);
611    }
612
613    #[test]
614    fn m3_inv_ok() {
615        let m = Matrix3x3::new([
616            [2.0, -1.0, 0.0],
617            [-1.0, 2.0, -1.0],
618            [0.0, -1.0, 2.0],
619        ]);
620        let inv = m.inv().unwrap();
621        let i = m.mul(&inv);
622        for r in 0..3 {
623            for c in 0..3 {
624                let expected = if r == c { 1.0 } else { 0.0 };
625                assert!((i.get(r, c) - expected).abs() < 1e-5,
626                    "i[{r}][{c}] = {} expected {expected}", i.get(r, c));
627            }
628        }
629    }
630
631    #[test]
632    fn m3_inv_singular() {
633        let m = Matrix3x3::new([
634            [1.0, 2.0, 3.0],
635            [4.0, 5.0, 6.0],
636            [7.0, 8.0, 9.0],
637        ]);
638        assert_eq!(m.inv(), Err(MatrixError::SingularMatrix));
639    }
640
641    #[test]
642    fn m3_scale() {
643        let m = Matrix3x3::identity();
644        let s = m.scale(3.0);
645        assert!((s.get(0, 0) - 3.0).abs() < 1e-6);
646        assert!((s.get(0, 1)).abs() < 1e-6);
647    }
648
649    // Opérateurs Matrix2x2
650    #[test]
651    fn m2_ops_add() {
652        let a = Matrix2x2::new([[1.0, 2.0], [3.0, 4.0]]);
653        let b = Matrix2x2::new([[1.0, 0.0], [0.0, 1.0]]);
654        let c = a + b;
655        assert!((c.get(0, 0) - 2.0).abs() < 1e-6);
656        assert!((c.get(1, 1) - 5.0).abs() < 1e-6);
657    }
658
659    #[test]
660    fn m2_ops_sub() {
661        let a = Matrix2x2::new([[3.0, 2.0], [1.0, 4.0]]);
662        let b = Matrix2x2::new([[1.0, 1.0], [1.0, 1.0]]);
663        let c = a - b;
664        assert!((c.get(0, 0) - 2.0).abs() < 1e-6);
665        assert!((c.get(1, 1) - 3.0).abs() < 1e-6);
666    }
667
668    #[test]
669    fn m2_ops_mul_matrix() {
670        let a = Matrix2x2::new([[1.0, 2.0], [3.0, 4.0]]);
671        let b = Matrix2x2::new([[2.0, 0.0], [1.0, 3.0]]);
672        let c = a * b;
673        assert!((c.get(0, 0) - 4.0).abs() < 1e-6);
674        assert!((c.get(0, 1) - 6.0).abs() < 1e-6);
675    }
676
677    #[test]
678    fn m2_ops_mul_scalar() {
679        let a = Matrix2x2::new([[1.0, 2.0], [3.0, 4.0]]);
680        let b = a * 3.0;
681        assert!((b.get(0, 0) - 3.0).abs() < 1e-6);
682        assert!((b.get(1, 1) - 12.0).abs() < 1e-6);
683    }
684
685    #[test]
686    fn m2_ops_neg() {
687        let a = Matrix2x2::new([[1.0, 2.0], [3.0, 4.0]]);
688        let b = -a;
689        assert!((b.get(0, 0) + 1.0).abs() < 1e-6);
690        assert!((b.get(1, 1) + 4.0).abs() < 1e-6);
691    }
692
693    //  Opérateurs Matrix3x3 
694
695    #[test]
696    fn m3_ops_add() {
697        let a = Matrix3x3::identity();
698        let b = Matrix3x3::identity();
699        let c = a + b;
700        assert!((c.get(0, 0) - 2.0).abs() < 1e-6);
701        assert!((c.get(0, 1)).abs() < 1e-6);
702    }
703
704    #[test]
705    fn m3_ops_sub() {
706        let a = Matrix3x3::identity();
707        let b = Matrix3x3::identity();
708        let c = a - b;
709        assert!(c.get(0, 0).abs() < 1e-6);
710    }
711
712    #[test]
713    fn m3_ops_mul_matrix() {
714        let a = Matrix3x3::new([
715            [1.0, 2.0, 3.0],
716            [0.0, 1.0, 4.0],
717            [5.0, 6.0, 0.0],
718        ]);
719        let i = Matrix3x3::identity();
720        let c = a * i;
721        for r in 0..3 {
722            for col in 0..3 {
723                assert!((c.get(r, col) - a.get(r, col)).abs() < 1e-6);
724            }
725        }
726    }
727
728    #[test]
729    fn m3_ops_mul_scalar() {
730        let a = Matrix3x3::identity();
731        let b = a * 5.0;
732        assert!((b.get(0, 0) - 5.0).abs() < 1e-6);
733        assert!((b.get(0, 1)).abs() < 1e-6);
734    }
735
736    #[test]
737    fn m3_ops_neg() {
738        let a = Matrix3x3::identity();
739        let b = -a;
740        assert!((b.get(0, 0) + 1.0).abs() < 1e-6);
741        assert!((b.get(1, 1) + 1.0).abs() < 1e-6);
742    }
743}