glam_matrix_extras/symmetric/
symmetric_mat3.rs

1use core::iter::Sum;
2use core::ops::*;
3#[cfg(feature = "f64")]
4use glam::{DMat3, DVec3};
5use glam::{Mat3, Vec3, Vec3A};
6
7#[cfg(feature = "bevy_reflect")]
8use bevy_reflect::{Reflect, ReflectDeserialize, ReflectSerialize, std_traits::ReflectDefault};
9
10use crate::{MatConversionError, SquareMatExt, ops::FloatAbs};
11
12#[cfg(feature = "f64")]
13use crate::rectangular::{DMat23, DMat32};
14#[cfg(feature = "f32")]
15use crate::rectangular::{Mat23, Mat32};
16
17/// An extension trait for 3x3 matrices.
18pub trait Mat3Ext {
19    /// The type of the symmetric 3x3 matrix.
20    type SymmetricMat3;
21
22    /// Multiplies `self` by a symmetric 3x3 matrix.
23    fn mul_symmetric_mat3(&self, rhs: &Self::SymmetricMat3) -> Self;
24
25    /// Adds a symmetric 3x3 matrix to `self`.
26    fn add_symmetric_mat3(&self, rhs: &Self::SymmetricMat3) -> Self;
27
28    /// Subtracts a symmetric 3x3 matrix from `self`.
29    fn sub_symmetric_mat3(&self, rhs: &Self::SymmetricMat3) -> Self;
30}
31
32#[cfg(feature = "f32")]
33impl Mat3Ext for Mat3 {
34    type SymmetricMat3 = SymmetricMat3;
35
36    #[inline]
37    fn mul_symmetric_mat3(&self, rhs: &SymmetricMat3) -> Mat3 {
38        self.mul(rhs)
39    }
40
41    #[inline]
42    fn add_symmetric_mat3(&self, rhs: &SymmetricMat3) -> Mat3 {
43        self.add(rhs)
44    }
45
46    #[inline]
47    fn sub_symmetric_mat3(&self, rhs: &SymmetricMat3) -> Mat3 {
48        self.sub(rhs)
49    }
50}
51
52#[cfg(feature = "f64")]
53impl Mat3Ext for DMat3 {
54    type SymmetricMat3 = SymmetricDMat3;
55
56    #[inline]
57    fn mul_symmetric_mat3(&self, rhs: &SymmetricDMat3) -> DMat3 {
58        self.mul(rhs)
59    }
60
61    #[inline]
62    fn add_symmetric_mat3(&self, rhs: &SymmetricDMat3) -> DMat3 {
63        self.add(rhs)
64    }
65
66    #[inline]
67    fn sub_symmetric_mat3(&self, rhs: &SymmetricDMat3) -> DMat3 {
68        self.sub(rhs)
69    }
70}
71
72macro_rules! symmetric_mat3s {
73    ($($n:ident => $nonsymmetricn:ident, $m23t:ident, $m32t:ident, $v2t:ident, $vt:ident, $t:ident),+) => {
74        $(
75        /// The bottom left triangle (including the diagonal) of a symmetric 3x3 column-major matrix.
76        ///
77        /// This is useful for storing a symmetric 3x3 matrix in a more compact form and performing some
78        /// matrix operations more efficiently.
79        ///
80        /// Some defining properties of symmetric matrices include:
81        ///
82        /// - The matrix is equal to its transpose.
83        /// - The matrix has real eigenvalues.
84        /// - The eigenvectors corresponding to the eigenvalues are orthogonal.
85        /// - The matrix is always diagonalizable.
86        ///
87        /// The sum and difference of two symmetric matrices is always symmetric.
88        /// However, the product of two symmetric matrices is *only* symmetric
89        /// if the matrices are commutable, meaning that `AB = BA`.
90        #[derive(Clone, Copy, PartialEq)]
91        #[cfg_attr(feature = "bevy_reflect", derive(Reflect))]
92        #[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
93        #[cfg_attr(
94            all(feature = "bevy_reflect", feature = "serde"),
95            reflect(Debug, Default, PartialEq, Serialize, Deserialize)
96        )]
97        pub struct $n {
98            /// The first element of the first column.
99            pub m00: $t,
100            /// The second element of the first column.
101            pub m01: $t,
102            /// The third element of the first column.
103            pub m02: $t,
104            /// The second element of the second column.
105            pub m11: $t,
106            /// The third element of the second column.
107            pub m12: $t,
108            /// The third element of the third column.
109            pub m22: $t,
110        }
111
112        impl $n {
113            /// A symmetric 3x3 matrix with all elements set to `0.0`.
114            pub const ZERO: Self = Self::new(0.0, 0.0, 0.0, 0.0, 0.0, 0.0);
115
116            /// A symmetric 3x3 identity matrix, where all diagonal elements are `1.0`,
117            /// and all off-diagonal elements are `0.0`.
118            pub const IDENTITY: Self = Self::new(1.0, 0.0, 0.0, 1.0, 0.0, 1.0);
119
120            /// All NaNs.
121            pub const NAN: Self = Self::new(
122                $t::NAN,
123                $t::NAN,
124                $t::NAN,
125                $t::NAN,
126                $t::NAN,
127                $t::NAN,
128            );
129
130            /// Creates a new symmetric 3x3 matrix from its bottom left triangle, including diagonal elements.
131            ///
132            /// The elements are in column-major order `mCR`, where `C` is the column index
133            /// and `R` is the row index.
134            #[inline(always)]
135            #[must_use]
136            pub const fn new(
137                m00: $t,
138                m01: $t,
139                m02: $t,
140                m11: $t,
141                m12: $t,
142                m22: $t,
143            ) -> Self {
144                Self {
145                    m00,
146                    m01,
147                    m02,
148                    m11,
149                    m12,
150                    m22,
151                }
152            }
153
154            /// Creates a symmetric 3x3 matrix from three column vectors.
155            ///
156            /// Only the lower left triangle of the matrix is used. No check is performed to ensure
157            /// that the given columns truly produce a symmetric matrix.
158            #[inline(always)]
159            #[must_use]
160            pub const fn from_cols_unchecked(x_axis: $vt, y_axis: $vt, z_axis: $vt) -> Self {
161                Self {
162                    m00: x_axis.x,
163                    m01: x_axis.y,
164                    m02: x_axis.z,
165                    m11: y_axis.y,
166                    m12: y_axis.z,
167                    m22: z_axis.z,
168                }
169            }
170
171            /// Creates a symmetric 3x3 matrix from an array stored in column major order.
172            ///
173            /// Only the lower left triangle of the matrix is used. No check is performed to ensure
174            /// that the given columns truly produce a symmetric matrix.
175            #[inline]
176            #[must_use]
177            pub const fn from_cols_array_unchecked(m: &[$t; 9]) -> Self {
178                Self::new(m[0], m[1], m[2], m[4], m[5], m[8])
179            }
180
181            /// Creates an array storing data in column major order.
182            #[inline]
183            #[must_use]
184            pub const fn to_cols_array(&self) -> [$t; 9] {
185                [
186                    self.m00, self.m01, self.m02, self.m01, self.m11, self.m12, self.m02, self.m12,
187                    self.m22,
188                ]
189            }
190
191            /// Creates a symmetric 3x3 matrix from a 2D array stored in column major order.
192            ///
193            /// Only the lower left triangle of the matrix is used. No check is performed to ensure
194            /// that the given columns truly produce a symmetric matrix.
195            #[inline]
196            #[must_use]
197            pub const fn from_cols_array_2d_unchecked(m: &[[$t; 3]; 3]) -> Self {
198                Self::from_cols_unchecked(
199                    $vt::from_array(m[0]),
200                    $vt::from_array(m[1]),
201                    $vt::from_array(m[2]),
202                )
203            }
204
205            /// Creates a 2D array storing data in column major order.
206            #[inline]
207            #[must_use]
208            pub const fn to_cols_array_2d(&self) -> [[$t; 3]; 3] {
209                [
210                    [self.m00, self.m01, self.m02],
211                    [self.m01, self.m11, self.m12],
212                    [self.m02, self.m12, self.m22],
213                ]
214            }
215
216            /// Creates a 3x3 matrix from the first 9 values in `slice`.
217            ///
218            /// Only the lower left triangle of the matrix is used. No check is performed to ensure
219            /// that the given columns truly produce a symmetric matrix.
220            ///
221            /// # Panics
222            ///
223            /// Panics if `slice` is less than 9 elements long.
224            #[inline]
225            #[must_use]
226            pub const fn from_cols_slice(slice: &[$t]) -> Self {
227                Self::new(slice[0], slice[1], slice[2], slice[4], slice[5], slice[8])
228            }
229
230            /// Creates a symmetric 3x3 matrix with its diagonal set to `diagonal` and all other entries set to `0.0`.
231            #[inline]
232            #[must_use]
233            #[doc(alias = "scale")]
234            pub const fn from_diagonal(diagonal: $vt) -> Self {
235                Self::new(diagonal.x, 0.0, 0.0, diagonal.y, 0.0, diagonal.z)
236            }
237
238            /// Tries to create a symmetric 3x3 matrix from a 3x3 matrix.
239            ///
240            /// # Errors
241            ///
242            /// Returns a [`MatConversionError`] if the given matrix is not symmetric.
243            #[inline]
244            pub fn try_from_mat3(mat: $nonsymmetricn) -> Result<Self, MatConversionError> {
245                if mat.is_symmetric() {
246                    Ok(Self::from_mat3_unchecked(mat))
247                } else {
248                    Err(MatConversionError::Asymmetric)
249                }
250            }
251
252            /// Creates a symmetric 3x3 matrix from a 3x3 matrix.
253            ///
254            /// Only the lower left triangle of the matrix is used. No check is performed to ensure
255            /// that the given matrix is truly symmetric.
256            #[inline]
257            #[must_use]
258            pub const fn from_mat3_unchecked(mat: $nonsymmetricn) -> Self {
259                Self::new(
260                    mat.x_axis.x,
261                    mat.x_axis.y,
262                    mat.x_axis.z,
263                    mat.y_axis.y,
264                    mat.y_axis.z,
265                    mat.z_axis.z,
266                )
267            }
268
269            /// Creates a 3x3 matrix from the symmetric 3x3 matrix in `self`.
270            #[inline]
271            #[must_use]
272            pub const fn to_mat3(&self) -> $nonsymmetricn {
273                $nonsymmetricn::from_cols_array(&self.to_cols_array())
274            }
275
276            /// Creates a new symmetric 3x3 matrix from the outer product `v * v^T`.
277            #[inline(always)]
278            #[must_use]
279            pub fn from_outer_product(v: $vt) -> Self {
280                Self::new(
281                    v.x * v.x,
282                    v.x * v.y,
283                    v.x * v.z,
284                    v.y * v.y,
285                    v.y * v.z,
286                    v.z * v.z,
287                )
288            }
289
290            /// Returns the matrix column for the given `index`.
291            ///
292            /// # Panics
293            ///
294            /// Panics if `index` is greater than 2.
295            #[inline]
296            #[must_use]
297            pub const fn col(&self, index: usize) -> $vt {
298                match index {
299                    0 => $vt::new(self.m00, self.m01, self.m02),
300                    1 => $vt::new(self.m01, self.m11, self.m12),
301                    2 => $vt::new(self.m02, self.m12, self.m22),
302                    _ => panic!("index out of bounds"),
303                }
304            }
305
306            /// Returns the matrix row for the given `index`.
307            ///
308            /// # Panics
309            ///
310            /// Panics if `index` is greater than 2.
311            #[inline]
312            #[must_use]
313            pub const fn row(&self, index: usize) -> $vt {
314                match index {
315                    0 => $vt::new(self.m00, self.m01, self.m02),
316                    1 => $vt::new(self.m01, self.m11, self.m12),
317                    2 => $vt::new(self.m02, self.m12, self.m22),
318                    _ => panic!("index out of bounds"),
319                }
320            }
321
322            /// Returns the diagonal of the matrix.
323            #[inline]
324            #[must_use]
325            pub fn diagonal(&self) -> $vt {
326                $vt::new(self.m00, self.m11, self.m22)
327            }
328
329            /// Returns `true` if, and only if, all elements are finite.
330            /// If any element is either `NaN` or positive or negative infinity, this will return `false`.
331            #[inline]
332            #[must_use]
333            pub fn is_finite(&self) -> bool {
334                self.m00.is_finite()
335                    && self.m01.is_finite()
336                    && self.m02.is_finite()
337                    && self.m11.is_finite()
338                    && self.m12.is_finite()
339                    && self.m22.is_finite()
340            }
341
342            /// Returns `true` if any elements are `NaN`.
343            #[inline]
344            #[must_use]
345            pub fn is_nan(&self) -> bool {
346                self.m00.is_nan()
347                    || self.m01.is_nan()
348                    || self.m02.is_nan()
349                    || self.m11.is_nan()
350                    || self.m12.is_nan()
351                    || self.m22.is_nan()
352            }
353
354            /// Returns the determinant of `self`.
355            #[inline]
356            #[must_use]
357            pub fn determinant(&self) -> $t {
358                //     [ a d e ]
359                // A = | d b f |
360                //     [ e f c ]
361                //
362                // det(A) = abc + 2def - af^2 - bd^2 - ce^2
363                let [a, b, c] = [self.m00, self.m11, self.m22];
364                let [d, e, f] = [self.m01, self.m02, self.m12];
365                a * b * c + 2.0 * d * e * f - a * f * f - b * d * d - c * e * e
366            }
367
368            /// Returns the inverse of `self`.
369            ///
370            /// If the matrix is not invertible the returned matrix will be invalid.
371            #[inline]
372            #[must_use]
373            pub fn inverse(&self) -> Self {
374                let m00 = self.m11 * self.m22 - self.m12 * self.m12;
375                let m01 = self.m12 * self.m02 - self.m22 * self.m01;
376                let m02 = self.m01 * self.m12 - self.m02 * self.m11;
377
378                let inverse_determinant = 1.0 / (m00 * self.m00 + m01 * self.m01 + m02 * self.m02);
379
380                let m11 = self.m22 * self.m00 - self.m02 * self.m02;
381                let m12 = self.m02 * self.m01 - self.m00 * self.m12;
382                let m22 = self.m00 * self.m11 - self.m01 * self.m01;
383
384                Self {
385                    m00: m00 * inverse_determinant,
386                    m01: m01 * inverse_determinant,
387                    m02: m02 * inverse_determinant,
388                    m11: m11 * inverse_determinant,
389                    m12: m12 * inverse_determinant,
390                    m22: m22 * inverse_determinant,
391                }
392            }
393
394            /// Returns the inverse of `self`, or a zero matrix if the matrix is not invertible.
395            #[inline]
396            #[must_use]
397            pub fn inverse_or_zero(&self) -> Self {
398                let m00 = self.m11 * self.m22 - self.m12 * self.m12;
399                let m01 = self.m12 * self.m02 - self.m22 * self.m01;
400                let m02 = self.m01 * self.m12 - self.m02 * self.m11;
401
402                let determinant = m00 * self.m00 + m01 * self.m01 + m02 * self.m02;
403
404                if determinant == 0.0 {
405                    return Self::ZERO;
406                }
407
408                let inverse_determinant = 1.0 / determinant;
409
410                let m11 = self.m22 * self.m00 - self.m02 * self.m02;
411                let m12 = self.m02 * self.m01 - self.m00 * self.m12;
412                let m22 = self.m00 * self.m11 - self.m01 * self.m01;
413
414                Self {
415                    m00: m00 * inverse_determinant,
416                    m01: m01 * inverse_determinant,
417                    m02: m02 * inverse_determinant,
418                    m11: m11 * inverse_determinant,
419                    m12: m12 * inverse_determinant,
420                    m22: m22 * inverse_determinant,
421                }
422            }
423
424            /// Takes the absolute value of each element in `self`.
425            #[inline]
426            #[must_use]
427            pub fn abs(&self) -> Self {
428                Self::new(
429                    FloatAbs::abs(self.m00),
430                    FloatAbs::abs(self.m01),
431                    FloatAbs::abs(self.m02),
432                    FloatAbs::abs(self.m11),
433                    FloatAbs::abs(self.m12),
434                    FloatAbs::abs(self.m22),
435                )
436            }
437
438            /// Computes `skew_symmetric(vec) * self * skew_symmetric(vec).transpose()` for a symmetric matrix `self`.
439            #[inline]
440            #[must_use]
441            pub fn skew(&self, vec: $vt) -> Self {
442                // 27 multiplications and 14 additions
443
444                let xzy = vec.x * self.m12;
445                let yzx = vec.y * self.m02;
446                let zyx = vec.z * self.m01;
447
448                let ixy = vec.y * self.m12 - vec.z * self.m11;
449                let ixz = vec.y * self.m22 - vec.z * self.m12;
450                let iyx = vec.z * self.m00 - vec.x * self.m02;
451                let iyy = zyx - xzy;
452
453                let iyz = vec.z * self.m02 - vec.x * self.m22;
454                let izx = vec.x * self.m01 - vec.y * self.m00;
455                let izy = vec.x * self.m11 - vec.y * self.m01;
456                let izz = xzy - yzx;
457
458                Self::new(
459                    vec.y * ixz - vec.z * ixy,
460                    vec.y * iyz - vec.z * iyy,
461                    vec.y * izz - vec.z * izy,
462                    vec.z * iyx - vec.x * iyz,
463                    vec.z * izx - vec.x * izz,
464                    vec.x * izy - vec.y * izx,
465                )
466            }
467
468            /// Transforms a 3D vector.
469            #[inline]
470            #[must_use]
471            pub fn mul_vec3(&self, rhs: $vt) -> $vt {
472                let mut res = self.col(0).mul(rhs.x);
473                res = res.add(self.col(1).mul(rhs.y));
474                res = res.add(self.col(2).mul(rhs.z));
475                res
476            }
477
478            /// Solves `self * x = rhs` for `x` using the LDLT decomposition.
479            ///
480            /// `self` must be a positive semidefinite matrix.
481            #[inline]
482            #[must_use]
483            pub fn ldlt_solve(&self, rhs: $vt) -> $vt {
484                let d1 = self.m00;
485                let inv_d1 = 1.0 / d1;
486                let l21 = inv_d1 * self.m01;
487                let l31 = inv_d1 * self.m02;
488                let d2 = self.m11 - l21 * l21 * d1;
489                let inv_d2 = 1.0 / d2;
490                let l32 = inv_d2 * (self.m12 - l21 * l31 * d1);
491                let d3 = self.m22 - l31 * l31 * d1 - l32 * l32 * d2;
492                let inv_d3 = 1.0 / d3;
493
494                // Forward substitution: Solve L * y = b
495                let y1 = rhs.x;
496                let y2 = rhs.y - l21 * y1;
497                let y3 = rhs.z - l31 * y1 - l32 * y2;
498
499                // Diagonal: Solve D * z = y
500                let z1 = y1 * inv_d1;
501                let z2 = y2 * inv_d2;
502                let z3 = y3 * inv_d3;
503
504                // Backward substitution: Solve L^T * x = z
505                let x3 = z3;
506                let x2 = z2 - l32 * x3;
507                let x1 = z1 - l21 * x2 - l31 * x3;
508
509                $vt::new(x1, x2, x3)
510            }
511
512            /// Multiplies two 3x3 matrices.
513            #[inline]
514            #[must_use]
515            pub fn mul_mat3(&self, rhs: &$nonsymmetricn) -> $nonsymmetricn {
516                self.mul(rhs)
517            }
518
519            /// Multiplies `self` by a 3x2 matrix, `self * rhs`.
520            #[inline]
521            #[must_use]
522            pub fn mul_mat32(&self, rhs: &$m32t) -> $m32t {
523                self.mul(rhs)
524            }
525
526            /// Computes `a * transpose(b)`, assuming `a = b * M` for some symmetric matrix `M`.
527            ///
528            /// This effectively completes the second half of the sandwich product `b * M * transpose(b)`.
529            #[inline]
530            #[must_use]
531            pub fn complete_mat23_sandwich(a: &$m23t, b: &$m23t) -> Self {
532                Self::new(
533                    a.col(0).dot(b.col(0)),
534                    a.col(1).dot(b.col(0)),
535                    a.col(2).dot(b.col(0)),
536                    a.col(1).dot(b.col(1)),
537                    a.col(2).dot(b.col(1)),
538                    a.col(2).dot(b.col(2)),
539                )
540            }
541
542            /// Computes `a * transpose(b)`, assuming `a = b * M` for some symmetric matrix `M`.
543            ///
544            /// This effectively completes the second half of the sandwich product `b * M * transpose(b)`.
545            #[inline]
546            #[must_use]
547            pub fn complete_mat32_sandwich(a: &$m32t, b: &$m32t) -> Self {
548                Self::new(
549                    a.row(0).dot(b.row(0)),
550                    a.row(1).dot(b.row(0)),
551                    a.row(2).dot(b.row(0)),
552                    a.row(1).dot(b.row(1)),
553                    a.row(2).dot(b.row(1)),
554                    a.row(2).dot(b.row(2)),
555                )
556            }
557
558            /// Adds two 3x3 matrices.
559            #[inline]
560            #[must_use]
561            pub fn add_mat3(&self, rhs: &$nonsymmetricn) -> $nonsymmetricn {
562                self.add(rhs)
563            }
564
565            /// Subtracts two 3x3 matrices.
566            #[inline]
567            #[must_use]
568            pub fn sub_mat3(&self, rhs: &$nonsymmetricn) -> $nonsymmetricn {
569                self.sub(rhs)
570            }
571
572            /// Multiplies two symmetric 3x3 matrices.
573            #[inline]
574            #[must_use]
575            pub fn mul_symmetric_mat3(&self, rhs: &Self) -> $nonsymmetricn {
576                self.mul(rhs)
577            }
578
579            /// Adds two symmetric 3x3 matrices.
580            #[inline]
581            #[must_use]
582            pub fn add_symmetric_mat3(&self, rhs: &Self) -> Self {
583                self.add(rhs)
584            }
585
586            /// Subtracts two symmetric 3x3 matrices.
587            #[inline]
588            #[must_use]
589            pub fn sub_symmetric_mat3(&self, rhs: &Self) -> Self {
590                self.sub(rhs)
591            }
592
593            /// Multiplies a 3x3 matrix by a scalar.
594            #[inline]
595            #[must_use]
596            pub fn mul_scalar(&self, rhs: $t) -> Self {
597                Self::new(
598                    self.m00 * rhs,
599                    self.m01 * rhs,
600                    self.m02 * rhs,
601                    self.m11 * rhs,
602                    self.m12 * rhs,
603                    self.m22 * rhs,
604                )
605            }
606
607            /// Divides a 3x3 matrix by a scalar.
608            #[inline]
609            #[must_use]
610            pub fn div_scalar(&self, rhs: $t) -> Self {
611                Self::new(
612                    self.m00 / rhs,
613                    self.m01 / rhs,
614                    self.m02 / rhs,
615                    self.m11 / rhs,
616                    self.m12 / rhs,
617                    self.m22 / rhs,
618                )
619            }
620        }
621
622        impl Default for $n {
623            #[inline(always)]
624            fn default() -> Self {
625                Self::IDENTITY
626            }
627        }
628
629        impl TryFrom<$nonsymmetricn> for $n {
630            type Error = MatConversionError;
631
632            #[inline]
633            fn try_from(mat: $nonsymmetricn) -> Result<Self, Self::Error> {
634                Self::try_from_mat3(mat)
635            }
636        }
637
638        impl Add for $n {
639            type Output = Self;
640            #[inline]
641            fn add(self, rhs: Self) -> Self::Output {
642                Self::new(
643                    self.m00 + rhs.m00,
644                    self.m01 + rhs.m01,
645                    self.m02 + rhs.m02,
646                    self.m11 + rhs.m11,
647                    self.m12 + rhs.m12,
648                    self.m22 + rhs.m22,
649                )
650            }
651        }
652
653        impl Add<&Self> for $n {
654            type Output = Self;
655            #[inline]
656            fn add(self, rhs: &Self) -> Self::Output {
657                self.add(*rhs)
658            }
659        }
660
661        impl Add<Self> for &$n {
662            type Output = $n;
663            #[inline]
664            fn add(self, rhs: Self) -> Self::Output {
665                (*self).add(rhs)
666            }
667        }
668
669        impl Add<&Self> for &$n {
670            type Output = $n;
671            #[inline]
672            fn add(self, rhs: &Self) -> Self::Output {
673                (*self).add(*rhs)
674            }
675        }
676
677        impl AddAssign for $n {
678            #[inline]
679            fn add_assign(&mut self, rhs: Self) {
680                *self = self.add(rhs);
681            }
682        }
683
684        impl AddAssign<&Self> for $n {
685            #[inline]
686            fn add_assign(&mut self, rhs: &Self) {
687                self.add_assign(*rhs);
688            }
689        }
690
691        impl Add<$nonsymmetricn> for $n {
692            type Output = $nonsymmetricn;
693            #[inline]
694            fn add(self, rhs: $nonsymmetricn) -> Self::Output {
695                $nonsymmetricn::from_cols(
696                    self.col(0).add(rhs.x_axis),
697                    self.col(1).add(rhs.y_axis),
698                    self.col(2).add(rhs.z_axis),
699                )
700            }
701        }
702
703        impl Add<&$nonsymmetricn> for $n {
704            type Output = $nonsymmetricn;
705            #[inline]
706            fn add(self, rhs: &$nonsymmetricn) -> Self::Output {
707                self.add(*rhs)
708            }
709        }
710
711        impl Add<$nonsymmetricn> for &$n {
712            type Output = $nonsymmetricn;
713            #[inline]
714            fn add(self, rhs: $nonsymmetricn) -> Self::Output {
715                (*self).add(rhs)
716            }
717        }
718
719        impl Add<&$nonsymmetricn> for &$n {
720            type Output = $nonsymmetricn;
721            #[inline]
722            fn add(self, rhs: &$nonsymmetricn) -> Self::Output {
723                (*self).add(*rhs)
724            }
725        }
726
727        impl Add<$n> for $nonsymmetricn {
728            type Output = $nonsymmetricn;
729            #[inline]
730            fn add(self, rhs: $n) -> Self::Output {
731                rhs.add(&self)
732            }
733        }
734
735        impl Add<&$n> for $nonsymmetricn {
736            type Output = $nonsymmetricn;
737            #[inline]
738            fn add(self, rhs: &$n) -> Self::Output {
739                self.add(*rhs)
740            }
741        }
742
743        impl Add<&$n> for &$nonsymmetricn {
744            type Output = $nonsymmetricn;
745            #[inline]
746            fn add(self, rhs: &$n) -> Self::Output {
747                (*self).add(*rhs)
748            }
749        }
750
751        impl AddAssign<$n> for $nonsymmetricn {
752            #[inline]
753            fn add_assign(&mut self, rhs: $n) {
754                *self = self.add(rhs);
755            }
756        }
757
758        impl AddAssign<&$n> for $nonsymmetricn {
759            #[inline]
760            fn add_assign(&mut self, rhs: &$n) {
761                *self = self.add(*rhs);
762            }
763        }
764
765        impl Sub for $n {
766            type Output = Self;
767            #[inline]
768            fn sub(self, rhs: Self) -> Self::Output {
769                Self::new(
770                    self.m00 - rhs.m00,
771                    self.m01 - rhs.m01,
772                    self.m02 - rhs.m02,
773                    self.m11 - rhs.m11,
774                    self.m12 - rhs.m12,
775                    self.m22 - rhs.m22,
776                )
777            }
778        }
779
780        impl Sub<&Self> for $n {
781            type Output = Self;
782            #[inline]
783            fn sub(self, rhs: &Self) -> Self::Output {
784                self.sub(*rhs)
785            }
786        }
787
788        impl Sub<Self> for &$n {
789            type Output = $n;
790            #[inline]
791            fn sub(self, rhs: Self) -> Self::Output {
792                (*self).sub(rhs)
793            }
794        }
795
796        impl Sub<&Self> for &$n {
797            type Output = $n;
798            #[inline]
799            fn sub(self, rhs: &Self) -> Self::Output {
800                (*self).sub(*rhs)
801            }
802        }
803
804        impl SubAssign for $n {
805            #[inline]
806            fn sub_assign(&mut self, rhs: Self) {
807                *self = self.sub(rhs);
808            }
809        }
810
811        impl SubAssign<&Self> for $n {
812            #[inline]
813            fn sub_assign(&mut self, rhs: &Self) {
814                self.sub_assign(*rhs);
815            }
816        }
817
818        impl Sub<$nonsymmetricn> for $n {
819            type Output = $nonsymmetricn;
820            #[inline]
821            fn sub(self, rhs: $nonsymmetricn) -> Self::Output {
822                $nonsymmetricn::from_cols(
823                    self.col(0).sub(rhs.x_axis),
824                    self.col(1).sub(rhs.y_axis),
825                    self.col(2).sub(rhs.z_axis),
826                )
827            }
828        }
829
830        impl Sub<&$nonsymmetricn> for $n {
831            type Output = $nonsymmetricn;
832            #[inline]
833            fn sub(self, rhs: &$nonsymmetricn) -> Self::Output {
834                self.sub(*rhs)
835            }
836        }
837
838        impl Sub<$nonsymmetricn> for &$n {
839            type Output = $nonsymmetricn;
840            #[inline]
841            fn sub(self, rhs: $nonsymmetricn) -> Self::Output {
842                (*self).sub(rhs)
843            }
844        }
845
846        impl Sub<&$nonsymmetricn> for &$n {
847            type Output = $nonsymmetricn;
848            #[inline]
849            fn sub(self, rhs: &$nonsymmetricn) -> Self::Output {
850                (*self).sub(*rhs)
851            }
852        }
853
854        impl Sub<$n> for $nonsymmetricn {
855            type Output = $nonsymmetricn;
856            #[inline]
857            fn sub(self, rhs: $n) -> Self::Output {
858                rhs.sub(&self)
859            }
860        }
861
862        impl Sub<&$n> for $nonsymmetricn {
863            type Output = $nonsymmetricn;
864            #[inline]
865            fn sub(self, rhs: &$n) -> Self::Output {
866                self.sub(*rhs)
867            }
868        }
869
870        impl Sub<&$n> for &$nonsymmetricn {
871            type Output = $nonsymmetricn;
872            #[inline]
873            fn sub(self, rhs: &$n) -> Self::Output {
874                (*self).sub(*rhs)
875            }
876        }
877
878        impl SubAssign<$n> for $nonsymmetricn {
879            #[inline]
880            fn sub_assign(&mut self, rhs: $n) {
881                *self = self.sub(rhs);
882            }
883        }
884
885        impl SubAssign<&$n> for $nonsymmetricn {
886            #[inline]
887            fn sub_assign(&mut self, rhs: &$n) {
888                *self = self.sub(*rhs);
889            }
890        }
891
892        impl Neg for $n {
893            type Output = Self;
894            #[inline]
895            fn neg(self) -> Self::Output {
896                Self::new(
897                    -self.m00,
898                    -self.m01,
899                    -self.m02,
900                    -self.m11,
901                    -self.m12,
902                    -self.m22,
903                )
904            }
905        }
906
907        impl Neg for &$n {
908            type Output = $n;
909            #[inline]
910            fn neg(self) -> Self::Output {
911                (*self).neg()
912            }
913        }
914
915        impl Mul for $n {
916            type Output = $nonsymmetricn;
917            #[inline]
918            fn mul(self, rhs: Self) -> Self::Output {
919                $nonsymmetricn::from_cols(
920                    self.mul(rhs.col(0)),
921                    self.mul(rhs.col(1)),
922                    self.mul(rhs.col(2)),
923                )
924            }
925        }
926
927        impl Mul<&Self> for $n {
928            type Output = $nonsymmetricn;
929            #[inline]
930            fn mul(self, rhs: &Self) -> Self::Output {
931                self.mul(*rhs)
932            }
933        }
934
935        impl Mul<Self> for &$n {
936            type Output = $nonsymmetricn;
937            #[inline]
938            fn mul(self, rhs: Self) -> Self::Output {
939                (*self).mul(rhs)
940            }
941        }
942
943        impl Mul<&Self> for &$n {
944            type Output = $nonsymmetricn;
945            #[inline]
946            fn mul(self, rhs: &Self) -> Self::Output {
947                (*self).mul(*rhs)
948            }
949        }
950
951        impl Mul<$n> for $nonsymmetricn {
952            type Output = Self;
953            #[inline]
954            fn mul(self, rhs: $n) -> Self::Output {
955                Self::from_cols_array_2d(&[
956                    [
957                        self.x_axis.x * rhs.m00 + self.y_axis.x * rhs.m01 + self.z_axis.x * rhs.m02,
958                        self.x_axis.y * rhs.m00 + self.y_axis.y * rhs.m01 + self.z_axis.y * rhs.m02,
959                        self.x_axis.z * rhs.m00 + self.y_axis.z * rhs.m01 + self.z_axis.z * rhs.m02,
960                    ],
961                    [
962                        self.x_axis.x * rhs.m01 + self.y_axis.x * rhs.m11 + self.z_axis.x * rhs.m12,
963                        self.x_axis.y * rhs.m01 + self.y_axis.y * rhs.m11 + self.z_axis.y * rhs.m12,
964                        self.x_axis.z * rhs.m01 + self.y_axis.z * rhs.m11 + self.z_axis.z * rhs.m12,
965                    ],
966                    [
967                        self.x_axis.x * rhs.m02 + self.y_axis.x * rhs.m12 + self.z_axis.x * rhs.m22,
968                        self.x_axis.y * rhs.m02 + self.y_axis.y * rhs.m12 + self.z_axis.y * rhs.m22,
969                        self.x_axis.z * rhs.m02 + self.y_axis.z * rhs.m12 + self.z_axis.z * rhs.m22,
970                    ],
971                ])
972            }
973        }
974
975        impl Mul<&$n> for $nonsymmetricn {
976            type Output = Self;
977            #[inline]
978            fn mul(self, rhs: &$n) -> Self::Output {
979                self.mul(*rhs)
980            }
981        }
982
983        impl Mul<$n> for &$nonsymmetricn {
984            type Output = $nonsymmetricn;
985            #[inline]
986            fn mul(self, rhs: $n) -> Self::Output {
987                (*self).mul(rhs)
988            }
989        }
990
991        impl Mul<&$n> for &$nonsymmetricn {
992            type Output = $nonsymmetricn;
993            #[inline]
994            fn mul(self, rhs: &$n) -> Self::Output {
995                (*self).mul(*rhs)
996            }
997        }
998
999        impl MulAssign<$n> for $nonsymmetricn {
1000            #[inline]
1001            fn mul_assign(&mut self, rhs: $n) {
1002                *self = self.mul(rhs);
1003            }
1004        }
1005
1006        impl MulAssign<&$n> for $nonsymmetricn {
1007            #[inline]
1008            fn mul_assign(&mut self, rhs: &$n) {
1009                *self = self.mul(*rhs);
1010            }
1011        }
1012
1013        impl Mul<$nonsymmetricn> for $n {
1014            type Output = $nonsymmetricn;
1015            #[inline]
1016            fn mul(self, rhs: $nonsymmetricn) -> Self::Output {
1017                $nonsymmetricn::from_cols(
1018                    self.mul(rhs.x_axis),
1019                    self.mul(rhs.y_axis),
1020                    self.mul(rhs.z_axis),
1021                )
1022            }
1023        }
1024
1025        impl Mul<&$nonsymmetricn> for $n {
1026            type Output = $nonsymmetricn;
1027            #[inline]
1028            fn mul(self, rhs: &$nonsymmetricn) -> Self::Output {
1029                self.mul(*rhs)
1030            }
1031        }
1032
1033        impl Mul<$nonsymmetricn> for &$n {
1034            type Output = $nonsymmetricn;
1035            #[inline]
1036            fn mul(self, rhs: $nonsymmetricn) -> Self::Output {
1037                (*self).mul(rhs)
1038            }
1039        }
1040
1041        impl Mul<&$nonsymmetricn> for &$n {
1042            type Output = $nonsymmetricn;
1043            #[inline]
1044            fn mul(self, rhs: &$nonsymmetricn) -> Self::Output {
1045                (*self).mul(*rhs)
1046            }
1047        }
1048
1049        impl Mul<$m32t> for $n {
1050            type Output = $m32t;
1051            #[inline]
1052            fn mul(self, rhs: $m32t) -> Self::Output {
1053                $m32t::from_cols(
1054                    $vt::new(
1055                        self.row(0).dot(rhs.x_axis),
1056                        self.row(1).dot(rhs.x_axis),
1057                        self.row(2).dot(rhs.x_axis),
1058                    ),
1059                    $vt::new(
1060                        self.row(0).dot(rhs.y_axis),
1061                        self.row(1).dot(rhs.y_axis),
1062                        self.row(2).dot(rhs.y_axis),
1063                    ),
1064                )
1065            }
1066        }
1067
1068        impl Mul<&$m32t> for $n {
1069            type Output = $m32t;
1070            #[inline]
1071            fn mul(self, rhs: &$m32t) -> Self::Output {
1072                self.mul(*rhs)
1073            }
1074        }
1075
1076        impl Mul<$m32t> for &$n {
1077            type Output = $m32t;
1078            #[inline]
1079            fn mul(self, rhs: $m32t) -> Self::Output {
1080                (*self).mul(rhs)
1081            }
1082        }
1083
1084        impl Mul<&$m32t> for &$n {
1085            type Output = $m32t;
1086            #[inline]
1087            fn mul(self, rhs: &$m32t) -> Self::Output {
1088                (*self).mul(*rhs)
1089            }
1090        }
1091
1092        impl Mul<$vt> for $n {
1093            type Output = $vt;
1094            #[inline]
1095            fn mul(self, rhs: $vt) -> Self::Output {
1096                self.mul_vec3(rhs)
1097            }
1098        }
1099
1100        impl Mul<&$vt> for $n {
1101            type Output = $vt;
1102            #[inline]
1103            fn mul(self, rhs: &$vt) -> Self::Output {
1104                self.mul(*rhs)
1105            }
1106        }
1107
1108        impl Mul<$vt> for &$n {
1109            type Output = $vt;
1110            #[inline]
1111            fn mul(self, rhs: $vt) -> Self::Output {
1112                (*self).mul(rhs)
1113            }
1114        }
1115
1116        impl Mul<&$vt> for &$n {
1117            type Output = $vt;
1118            #[inline]
1119            fn mul(self, rhs: &$vt) -> Self::Output {
1120                (*self).mul(*rhs)
1121            }
1122        }
1123
1124        impl Mul<$n> for $t {
1125            type Output = $n;
1126            #[inline]
1127            fn mul(self, rhs: $n) -> Self::Output {
1128                rhs.mul_scalar(self)
1129            }
1130        }
1131
1132        impl Mul<&$n> for $t {
1133            type Output = $n;
1134            #[inline]
1135            fn mul(self, rhs: &$n) -> Self::Output {
1136                self.mul(*rhs)
1137            }
1138        }
1139
1140        impl Mul<$n> for &$t {
1141            type Output = $n;
1142            #[inline]
1143            fn mul(self, rhs: $n) -> Self::Output {
1144                (*self).mul(rhs)
1145            }
1146        }
1147
1148        impl Mul<&$n> for &$t {
1149            type Output = $n;
1150            #[inline]
1151            fn mul(self, rhs: &$n) -> Self::Output {
1152                (*self).mul(*rhs)
1153            }
1154        }
1155
1156        impl Mul<$t> for $n {
1157            type Output = Self;
1158            #[inline]
1159            fn mul(self, rhs: $t) -> Self::Output {
1160                self.mul_scalar(rhs)
1161            }
1162        }
1163
1164        impl Mul<&$t> for $n {
1165            type Output = Self;
1166            #[inline]
1167            fn mul(self, rhs: &$t) -> Self::Output {
1168                self.mul(*rhs)
1169            }
1170        }
1171
1172        impl Mul<$t> for &$n {
1173            type Output = $n;
1174            #[inline]
1175            fn mul(self, rhs: $t) -> Self::Output {
1176                (*self).mul(rhs)
1177            }
1178        }
1179
1180        impl Mul<&$t> for &$n {
1181            type Output = $n;
1182            #[inline]
1183            fn mul(self, rhs: &$t) -> Self::Output {
1184                (*self).mul(*rhs)
1185            }
1186        }
1187
1188        impl MulAssign<$t> for $n {
1189            #[inline]
1190            fn mul_assign(&mut self, rhs: $t) {
1191                *self = self.mul(rhs);
1192            }
1193        }
1194
1195        impl MulAssign<&$t> for $n {
1196            #[inline]
1197            fn mul_assign(&mut self, rhs: &$t) {
1198                self.mul_assign(*rhs);
1199            }
1200        }
1201
1202        impl Div<$n> for $t {
1203            type Output = $n;
1204            #[inline]
1205            fn div(self, rhs: $n) -> Self::Output {
1206                rhs.div_scalar(self)
1207            }
1208        }
1209
1210        impl Div<&$n> for $t {
1211            type Output = $n;
1212            #[inline]
1213            fn div(self, rhs: &$n) -> Self::Output {
1214                self.div(*rhs)
1215            }
1216        }
1217
1218        impl Div<$n> for &$t {
1219            type Output = $n;
1220            #[inline]
1221            fn div(self, rhs: $n) -> Self::Output {
1222                (*self).div(rhs)
1223            }
1224        }
1225
1226        impl Div<&$n> for &$t {
1227            type Output = $n;
1228            #[inline]
1229            fn div(self, rhs: &$n) -> Self::Output {
1230                (*self).div(*rhs)
1231            }
1232        }
1233
1234        impl Div<$t> for $n {
1235            type Output = Self;
1236            #[inline]
1237            fn div(self, rhs: $t) -> Self::Output {
1238                self.div_scalar(rhs)
1239            }
1240        }
1241
1242        impl Div<&$t> for $n {
1243            type Output = Self;
1244            #[inline]
1245            fn div(self, rhs: &$t) -> Self::Output {
1246                self.div(*rhs)
1247            }
1248        }
1249
1250        impl Div<$t> for &$n {
1251            type Output = $n;
1252            #[inline]
1253            fn div(self, rhs: $t) -> Self::Output {
1254                (*self).div(rhs)
1255            }
1256        }
1257
1258        impl Div<&$t> for &$n {
1259            type Output = $n;
1260            #[inline]
1261            fn div(self, rhs: &$t) -> Self::Output {
1262                (*self).div(*rhs)
1263            }
1264        }
1265
1266        impl DivAssign<$t> for $n {
1267            #[inline]
1268            fn div_assign(&mut self, rhs: $t) {
1269                *self = self.div(rhs);
1270            }
1271        }
1272
1273        impl DivAssign<&$t> for $n {
1274            #[inline]
1275            fn div_assign(&mut self, rhs: &$t) {
1276                self.div_assign(*rhs);
1277            }
1278        }
1279
1280        impl From<$n> for $nonsymmetricn {
1281            #[inline]
1282            fn from(mat: $n) -> Self {
1283                mat.to_mat3()
1284            }
1285        }
1286
1287        impl Sum<$n> for $n {
1288            fn sum<I: Iterator<Item = $n>>(iter: I) -> Self {
1289                iter.fold(Self::ZERO, Self::add)
1290            }
1291        }
1292
1293        impl<'a> Sum<&'a $n> for $n {
1294            fn sum<I: Iterator<Item = &'a $n>>(iter: I) -> Self {
1295                iter.fold(Self::ZERO, |a, &b| a.add(b))
1296            }
1297        }
1298
1299        #[cfg(feature = "approx")]
1300        impl approx::AbsDiffEq for $n {
1301            type Epsilon = $t;
1302
1303            #[inline]
1304            fn default_epsilon() -> Self::Epsilon {
1305                $t::default_epsilon()
1306            }
1307
1308            #[inline]
1309            fn abs_diff_eq(&self, other: &Self, epsilon: Self::Epsilon) -> bool {
1310                self.m00.abs_diff_eq(&other.m00, epsilon)
1311                    && self.m01.abs_diff_eq(&other.m01, epsilon)
1312                    && self.m02.abs_diff_eq(&other.m02, epsilon)
1313                    && self.m11.abs_diff_eq(&other.m11, epsilon)
1314                    && self.m12.abs_diff_eq(&other.m12, epsilon)
1315                    && self.m22.abs_diff_eq(&other.m22, epsilon)
1316            }
1317        }
1318
1319        #[cfg(feature = "approx")]
1320        impl approx::RelativeEq for $n {
1321            #[inline]
1322            fn default_max_relative() -> Self::Epsilon {
1323                $t::default_max_relative()
1324            }
1325
1326            #[inline]
1327            fn relative_eq(
1328                &self,
1329                other: &Self,
1330                epsilon: Self::Epsilon,
1331                max_relative: Self::Epsilon,
1332            ) -> bool {
1333                self.m00.relative_eq(&other.m00, epsilon, max_relative)
1334                    && self.m01.relative_eq(&other.m01, epsilon, max_relative)
1335                    && self.m02.relative_eq(&other.m02, epsilon, max_relative)
1336                    && self.m11.relative_eq(&other.m11, epsilon, max_relative)
1337                    && self.m12.relative_eq(&other.m12, epsilon, max_relative)
1338                    && self.m22.relative_eq(&other.m22, epsilon, max_relative)
1339            }
1340        }
1341
1342        #[cfg(feature = "approx")]
1343        impl approx::UlpsEq for $n {
1344            #[inline]
1345            fn default_max_ulps() -> u32 {
1346                $t::default_max_ulps()
1347            }
1348
1349            #[inline]
1350            fn ulps_eq(
1351                &self,
1352                other: &Self,
1353                epsilon: Self::Epsilon,
1354                max_ulps: u32,
1355            ) -> bool {
1356                self.m00.ulps_eq(&other.m00, epsilon, max_ulps)
1357                    && self.m01.ulps_eq(&other.m01, epsilon, max_ulps)
1358                    && self.m02.ulps_eq(&other.m02, epsilon, max_ulps)
1359                    && self.m11.ulps_eq(&other.m11, epsilon, max_ulps)
1360                    && self.m12.ulps_eq(&other.m12, epsilon, max_ulps)
1361                    && self.m22.ulps_eq(&other.m22, epsilon, max_ulps)
1362            }
1363        }
1364
1365        impl core::fmt::Debug for $n {
1366            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1367                f.debug_struct(stringify!($n))
1368                    .field("m00", &self.m00)
1369                    .field("m01", &self.m01)
1370                    .field("m02", &self.m02)
1371                    .field("m11", &self.m11)
1372                    .field("m12", &self.m12)
1373                    .field("m22", &self.m22)
1374                    .finish()
1375            }
1376        }
1377
1378        impl core::fmt::Display for $n {
1379            fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
1380                if let Some(p) = f.precision() {
1381                    write!(
1382                        f,
1383                        "[[{:.*}, {:.*}, {:.*}], [{:.*}, {:.*}, {:.*}], [{:.*}, {:.*}, {:.*}]]",
1384                        p, self.m00, p, self.m01, p, self.m02,
1385                        p, self.m01, p, self.m11, p, self.m12,
1386                        p, self.m02, p, self.m12, p, self.m22,
1387                    )
1388                } else {
1389                    write!(
1390                        f,
1391                        "[[{}, {}, {}], [{}, {}, {}], [{}, {}, {}]]",
1392                        self.m00, self.m01, self.m02,
1393                        self.m01, self.m11, self.m12,
1394                        self.m02, self.m12, self.m22,
1395                    )
1396                }
1397            }
1398        }
1399        )+
1400    }
1401}
1402
1403#[cfg(feature = "f32")]
1404impl SymmetricMat3 {
1405    /// Transforms a [`Vec3A`].
1406    #[inline]
1407    #[must_use]
1408    pub fn mul_vec3a(&self, rhs: Vec3A) -> Vec3A {
1409        self.mul_vec3(rhs.into()).into()
1410    }
1411}
1412
1413#[cfg(feature = "f32")]
1414impl Mul<Vec3A> for SymmetricMat3 {
1415    type Output = Vec3A;
1416    #[inline]
1417    fn mul(self, rhs: Vec3A) -> Self::Output {
1418        self.mul_vec3a(rhs)
1419    }
1420}
1421
1422#[cfg(feature = "f32")]
1423symmetric_mat3s!(SymmetricMat3 => Mat3, Mat23, Mat32, Vec2, Vec3, f32);
1424
1425#[cfg(feature = "f64")]
1426symmetric_mat3s!(SymmetricDMat3 => DMat3, DMat23, DMat32, DVec2, DVec3, f64);
1427
1428#[cfg(all(feature = "f32", feature = "f64"))]
1429impl SymmetricMat3 {
1430    /// Returns the double precision version of `self`.
1431    #[inline]
1432    #[must_use]
1433    pub fn as_symmetric_dmat3(&self) -> SymmetricDMat3 {
1434        SymmetricDMat3 {
1435            m00: self.m00 as f64,
1436            m01: self.m01 as f64,
1437            m02: self.m02 as f64,
1438            m11: self.m11 as f64,
1439            m12: self.m12 as f64,
1440            m22: self.m22 as f64,
1441        }
1442    }
1443}
1444
1445#[cfg(all(feature = "f32", feature = "f64"))]
1446impl SymmetricDMat3 {
1447    /// Returns the single precision version of `self`.
1448    #[inline]
1449    #[must_use]
1450    pub fn as_symmetric_mat3(&self) -> SymmetricMat3 {
1451        SymmetricMat3 {
1452            m00: self.m00 as f32,
1453            m01: self.m01 as f32,
1454            m02: self.m02 as f32,
1455            m11: self.m11 as f32,
1456            m12: self.m12 as f32,
1457            m22: self.m22 as f32,
1458        }
1459    }
1460}
1461
1462#[cfg(test)]
1463mod tests {
1464    use approx::assert_relative_eq;
1465    use glam::Vec3;
1466
1467    use crate::SymmetricMat3;
1468
1469    #[test]
1470    fn ldlt_solve() {
1471        let mat = SymmetricMat3::new(4.0, 1.0, 5.0, 0.0, 2.0, 6.0);
1472
1473        // Known solution x
1474        let x = Vec3::new(1.0, 2.0, 3.0);
1475
1476        // Compute rhs = mat * x
1477        let rhs = mat.mul_vec3(x);
1478        assert_eq!(rhs, Vec3::new(21.0, 7.0, 27.0));
1479
1480        // Solve
1481        let sol = mat.ldlt_solve(rhs);
1482
1483        // Check solution
1484        assert_relative_eq!(sol, x, epsilon = 1e-4);
1485    }
1486
1487    #[test]
1488    fn ldlt_solve_identity() {
1489        let mat = SymmetricMat3::IDENTITY;
1490
1491        // Known solution x
1492        let x = Vec3::new(7.0, -3.0, 2.5);
1493
1494        // Compute rhs = mat * x
1495        let rhs = mat.mul_vec3(x);
1496
1497        // Solve
1498        let sol = mat.ldlt_solve(rhs);
1499
1500        // Check solution
1501        assert_relative_eq!(sol, x, epsilon = 1e-6);
1502    }
1503}