faer_core/
matrix_ops.rs

1//! addition and subtraction of matrices
2
3use super::*;
4use crate::{
5    assert,
6    permutation::{Index, SignedIndex},
7    sparse,
8};
9
10/// Scalar value tag.
11pub struct Scalar {
12    __private: (),
13}
14/// Dense column vector tag.
15pub struct DenseCol {
16    __private: (),
17}
18/// Dense row vector tag.
19pub struct DenseRow {
20    __private: (),
21}
22/// Dense matrix tag.
23pub struct Dense {
24    __private: (),
25}
26/// Sparse column-major matrix tag.
27pub struct SparseColMat<I: Index> {
28    __private: PhantomData<I>,
29}
30/// Sparse row-major matrix tag.
31pub struct SparseRowMat<I: Index> {
32    __private: PhantomData<I>,
33}
34/// Diagonal matrix tag.
35pub struct Diag {
36    __private: (),
37}
38/// Scaling factor tag.
39pub struct Scale {
40    __private: (),
41}
42/// Permutation matrix tag.
43pub struct Perm<I> {
44    __private: PhantomData<I>,
45}
46
47/// Trait for describing the view and owning variants of a given matrix type tag.
48pub trait MatrixKind {
49    /// Immutable view type.
50    type Ref<'a, E: Entity>: Copy;
51    /// Mutable view type.
52    type Mut<'a, E: Entity>;
53    /// Owning type.
54    type Own<E: Entity>;
55}
56type KindRef<'a, E, K> = <K as MatrixKind>::Ref<'a, E>;
57type KindMut<'a, E, K> = <K as MatrixKind>::Mut<'a, E>;
58type KindOwn<E, K> = <K as MatrixKind>::Own<E>;
59
60impl MatrixKind for Scalar {
61    type Ref<'a, E: Entity> = &'a E;
62    type Mut<'a, E: Entity> = &'a mut E;
63    type Own<E: Entity> = E;
64}
65impl MatrixKind for DenseCol {
66    type Ref<'a, E: Entity> = ColRef<'a, E>;
67    type Mut<'a, E: Entity> = ColMut<'a, E>;
68    type Own<E: Entity> = Col<E>;
69}
70impl MatrixKind for DenseRow {
71    type Ref<'a, E: Entity> = RowRef<'a, E>;
72    type Mut<'a, E: Entity> = RowMut<'a, E>;
73    type Own<E: Entity> = Row<E>;
74}
75impl MatrixKind for Dense {
76    type Ref<'a, E: Entity> = MatRef<'a, E>;
77    type Mut<'a, E: Entity> = MatMut<'a, E>;
78    type Own<E: Entity> = Mat<E>;
79}
80impl<I: Index> MatrixKind for SparseColMat<I> {
81    type Ref<'a, E: Entity> = sparse::SparseColMatRef<'a, I, E>;
82    type Mut<'a, E: Entity> = sparse::SparseColMatMut<'a, I, E>;
83    type Own<E: Entity> = sparse::SparseColMat<I, E>;
84}
85impl<I: Index> MatrixKind for SparseRowMat<I> {
86    type Ref<'a, E: Entity> = sparse::SparseRowMatRef<'a, I, E>;
87    type Mut<'a, E: Entity> = sparse::SparseRowMatMut<'a, I, E>;
88    type Own<E: Entity> = sparse::SparseRowMat<I, E>;
89}
90impl MatrixKind for Scale {
91    type Ref<'a, E: Entity> = &'a MatScale<E>;
92    type Mut<'a, E: Entity> = &'a mut MatScale<E>;
93    type Own<E: Entity> = MatScale<E>;
94}
95impl MatrixKind for Diag {
96    type Ref<'a, E: Entity> = Matrix<inner::DiagRef<'a, E>>;
97    type Mut<'a, E: Entity> = Matrix<inner::DiagMut<'a, E>>;
98    type Own<E: Entity> = Matrix<inner::DiagOwn<E>>;
99}
100impl<I: Index> MatrixKind for Perm<I> {
101    type Ref<'a, E: Entity> = Matrix<inner::PermRef<'a, I, E>>;
102    type Mut<'a, E: Entity> = Matrix<inner::PermMut<'a, I, E>>;
103    type Own<E: Entity> = Matrix<inner::PermOwn<I, E>>;
104}
105
106/// Generic matrix trait.
107pub trait GenericMatrix: Sized {
108    /// Tag type.
109    type Kind: MatrixKind;
110    /// Scalar element type.
111    type Elem: Entity;
112
113    /// Returns a view over the matrix.
114    fn as_ref(this: &Matrix<Self>) -> <Self::Kind as MatrixKind>::Ref<'_, Self::Elem>;
115}
116/// Generic mutable matrix trait.
117pub trait GenericMatrixMut: GenericMatrix {
118    /// Returns a mutable over the matrix.
119    fn as_mut(this: &mut Matrix<Self>) -> <Self::Kind as MatrixKind>::Mut<'_, Self::Elem>;
120}
121
122impl<I: Index, E: Entity> GenericMatrix for inner::PermRef<'_, I, E> {
123    type Kind = Perm<I>;
124    type Elem = E;
125
126    #[inline(always)]
127    fn as_ref(this: &Matrix<Self>) -> <Self::Kind as MatrixKind>::Ref<'_, Self::Elem> {
128        *this
129    }
130}
131impl<I: Index, E: Entity> GenericMatrix for inner::PermMut<'_, I, E> {
132    type Kind = Perm<I>;
133    type Elem = E;
134
135    #[inline(always)]
136    fn as_ref(this: &Matrix<Self>) -> <Self::Kind as MatrixKind>::Ref<'_, Self::Elem> {
137        this.rb()
138    }
139}
140impl<I: Index, E: Entity> GenericMatrix for inner::PermOwn<I, E> {
141    type Kind = Perm<I>;
142    type Elem = E;
143
144    #[inline(always)]
145    fn as_ref(this: &Matrix<Self>) -> <Self::Kind as MatrixKind>::Ref<'_, Self::Elem> {
146        this.as_ref()
147    }
148}
149
150impl<E: Entity> GenericMatrix for inner::DenseRowRef<'_, E> {
151    type Kind = DenseRow;
152    type Elem = E;
153
154    #[inline(always)]
155    fn as_ref(this: &Matrix<Self>) -> <Self::Kind as MatrixKind>::Ref<'_, Self::Elem> {
156        *this
157    }
158}
159impl<E: Entity> GenericMatrix for inner::DenseRowMut<'_, E> {
160    type Kind = DenseRow;
161    type Elem = E;
162
163    #[inline(always)]
164    fn as_ref(this: &Matrix<Self>) -> <Self::Kind as MatrixKind>::Ref<'_, Self::Elem> {
165        this.rb()
166    }
167}
168impl<E: Entity> GenericMatrix for inner::DenseRowOwn<E> {
169    type Kind = DenseRow;
170    type Elem = E;
171
172    #[inline(always)]
173    fn as_ref(this: &Matrix<Self>) -> <Self::Kind as MatrixKind>::Ref<'_, Self::Elem> {
174        this.as_ref()
175    }
176}
177impl<E: Entity> GenericMatrixMut for inner::DenseRowMut<'_, E> {
178    #[inline(always)]
179    fn as_mut(this: &mut Matrix<Self>) -> <Self::Kind as MatrixKind>::Mut<'_, Self::Elem> {
180        this.rb_mut()
181    }
182}
183impl<E: Entity> GenericMatrixMut for inner::DenseRowOwn<E> {
184    #[inline(always)]
185    fn as_mut(this: &mut Matrix<Self>) -> <Self::Kind as MatrixKind>::Mut<'_, Self::Elem> {
186        this.as_mut()
187    }
188}
189
190impl<E: Entity> GenericMatrix for inner::DenseColRef<'_, E> {
191    type Kind = DenseCol;
192    type Elem = E;
193
194    #[inline(always)]
195    fn as_ref(this: &Matrix<Self>) -> <Self::Kind as MatrixKind>::Ref<'_, Self::Elem> {
196        *this
197    }
198}
199impl<E: Entity> GenericMatrix for inner::DenseColMut<'_, E> {
200    type Kind = DenseCol;
201    type Elem = E;
202
203    #[inline(always)]
204    fn as_ref(this: &Matrix<Self>) -> <Self::Kind as MatrixKind>::Ref<'_, Self::Elem> {
205        this.rb()
206    }
207}
208impl<E: Entity> GenericMatrix for inner::DenseColOwn<E> {
209    type Kind = DenseCol;
210    type Elem = E;
211
212    #[inline(always)]
213    fn as_ref(this: &Matrix<Self>) -> <Self::Kind as MatrixKind>::Ref<'_, Self::Elem> {
214        this.as_ref()
215    }
216}
217impl<E: Entity> GenericMatrixMut for inner::DenseColMut<'_, E> {
218    #[inline(always)]
219    fn as_mut(this: &mut Matrix<Self>) -> <Self::Kind as MatrixKind>::Mut<'_, Self::Elem> {
220        this.rb_mut()
221    }
222}
223impl<E: Entity> GenericMatrixMut for inner::DenseColOwn<E> {
224    #[inline(always)]
225    fn as_mut(this: &mut Matrix<Self>) -> <Self::Kind as MatrixKind>::Mut<'_, Self::Elem> {
226        this.as_mut()
227    }
228}
229
230impl<E: Entity> GenericMatrix for inner::DenseRef<'_, E> {
231    type Kind = Dense;
232    type Elem = E;
233
234    #[inline(always)]
235    fn as_ref(this: &Matrix<Self>) -> <Self::Kind as MatrixKind>::Ref<'_, Self::Elem> {
236        *this
237    }
238}
239impl<E: Entity> GenericMatrix for inner::DenseMut<'_, E> {
240    type Kind = Dense;
241    type Elem = E;
242
243    #[inline(always)]
244    fn as_ref(this: &Matrix<Self>) -> <Self::Kind as MatrixKind>::Ref<'_, Self::Elem> {
245        this.rb()
246    }
247}
248impl<E: Entity> GenericMatrix for inner::DenseOwn<E> {
249    type Kind = Dense;
250    type Elem = E;
251
252    #[inline(always)]
253    fn as_ref(this: &Matrix<Self>) -> <Self::Kind as MatrixKind>::Ref<'_, Self::Elem> {
254        this.as_ref()
255    }
256}
257impl<E: Entity> GenericMatrixMut for inner::DenseMut<'_, E> {
258    #[inline(always)]
259    fn as_mut(this: &mut Matrix<Self>) -> <Self::Kind as MatrixKind>::Mut<'_, Self::Elem> {
260        this.rb_mut()
261    }
262}
263impl<E: Entity> GenericMatrixMut for inner::DenseOwn<E> {
264    #[inline(always)]
265    fn as_mut(this: &mut Matrix<Self>) -> <Self::Kind as MatrixKind>::Mut<'_, Self::Elem> {
266        this.as_mut()
267    }
268}
269
270impl<E: Entity> GenericMatrix for inner::DiagRef<'_, E> {
271    type Kind = Diag;
272    type Elem = E;
273
274    #[inline(always)]
275    fn as_ref(this: &Matrix<Self>) -> <Self::Kind as MatrixKind>::Ref<'_, Self::Elem> {
276        *this
277    }
278}
279impl<E: Entity> GenericMatrix for inner::DiagMut<'_, E> {
280    type Kind = Diag;
281    type Elem = E;
282
283    #[inline(always)]
284    fn as_ref(this: &Matrix<Self>) -> <Self::Kind as MatrixKind>::Ref<'_, Self::Elem> {
285        this.rb()
286    }
287}
288impl<E: Entity> GenericMatrix for inner::DiagOwn<E> {
289    type Kind = Diag;
290    type Elem = E;
291
292    #[inline(always)]
293    fn as_ref(this: &Matrix<Self>) -> <Self::Kind as MatrixKind>::Ref<'_, Self::Elem> {
294        this.as_ref()
295    }
296}
297impl<E: Entity> GenericMatrixMut for inner::DiagMut<'_, E> {
298    #[inline(always)]
299    fn as_mut(this: &mut Matrix<Self>) -> <Self::Kind as MatrixKind>::Mut<'_, Self::Elem> {
300        this.rb_mut()
301    }
302}
303impl<E: Entity> GenericMatrixMut for inner::DiagOwn<E> {
304    #[inline(always)]
305    fn as_mut(this: &mut Matrix<Self>) -> <Self::Kind as MatrixKind>::Mut<'_, Self::Elem> {
306        this.as_mut()
307    }
308}
309
310impl<E: Entity> GenericMatrix for inner::Scale<E> {
311    type Kind = Scale;
312    type Elem = E;
313
314    #[inline(always)]
315    fn as_ref(this: &Matrix<Self>) -> <Self::Kind as MatrixKind>::Ref<'_, Self::Elem> {
316        this
317    }
318}
319impl<E: Entity> GenericMatrixMut for inner::Scale<E> {
320    #[inline(always)]
321    fn as_mut(this: &mut Matrix<Self>) -> <Self::Kind as MatrixKind>::Mut<'_, Self::Elem> {
322        this
323    }
324}
325
326impl<I: Index, E: Entity> GenericMatrix for inner::SparseColMatRef<'_, I, E> {
327    type Kind = SparseColMat<I>;
328    type Elem = E;
329
330    #[inline(always)]
331    fn as_ref(this: &Matrix<Self>) -> <Self::Kind as MatrixKind>::Ref<'_, Self::Elem> {
332        *this
333    }
334}
335
336impl<I: Index, E: Entity> GenericMatrix for inner::SparseRowMatRef<'_, I, E> {
337    type Kind = SparseRowMat<I>;
338    type Elem = E;
339
340    #[inline(always)]
341    fn as_ref(this: &Matrix<Self>) -> <Self::Kind as MatrixKind>::Ref<'_, Self::Elem> {
342        *this
343    }
344}
345
346impl<I: Index, E: Entity> GenericMatrix for inner::SparseColMatMut<'_, I, E> {
347    type Kind = SparseColMat<I>;
348    type Elem = E;
349
350    #[inline(always)]
351    fn as_ref(this: &Matrix<Self>) -> <Self::Kind as MatrixKind>::Ref<'_, Self::Elem> {
352        this.rb()
353    }
354}
355
356impl<I: Index, E: Entity> GenericMatrix for inner::SparseRowMatMut<'_, I, E> {
357    type Kind = SparseRowMat<I>;
358    type Elem = E;
359
360    #[inline(always)]
361    fn as_ref(this: &Matrix<Self>) -> <Self::Kind as MatrixKind>::Ref<'_, Self::Elem> {
362        this.rb()
363    }
364}
365
366impl<I: Index, E: Entity> GenericMatrixMut for inner::SparseColMatMut<'_, I, E> {
367    #[inline(always)]
368    fn as_mut(this: &mut Matrix<Self>) -> <Self::Kind as MatrixKind>::Mut<'_, Self::Elem> {
369        this.rb_mut()
370    }
371}
372
373impl<I: Index, E: Entity> GenericMatrixMut for inner::SparseRowMatMut<'_, I, E> {
374    #[inline(always)]
375    fn as_mut(this: &mut Matrix<Self>) -> <Self::Kind as MatrixKind>::Mut<'_, Self::Elem> {
376        this.rb_mut()
377    }
378}
379
380impl<I: Index, E: Entity> GenericMatrix for inner::SparseColMat<I, E> {
381    type Kind = SparseColMat<I>;
382    type Elem = E;
383
384    #[inline(always)]
385    fn as_ref(this: &Matrix<Self>) -> <Self::Kind as MatrixKind>::Ref<'_, Self::Elem> {
386        this.as_ref()
387    }
388}
389
390impl<I: Index, E: Entity> GenericMatrix for inner::SparseRowMat<I, E> {
391    type Kind = SparseRowMat<I>;
392    type Elem = E;
393
394    #[inline(always)]
395    fn as_ref(this: &Matrix<Self>) -> <Self::Kind as MatrixKind>::Ref<'_, Self::Elem> {
396        this.as_ref()
397    }
398}
399
400impl<I: Index, E: Entity> GenericMatrixMut for inner::SparseColMat<I, E> {
401    #[inline(always)]
402    fn as_mut(this: &mut Matrix<Self>) -> <Self::Kind as MatrixKind>::Mut<'_, Self::Elem> {
403        this.as_mut()
404    }
405}
406
407impl<I: Index, E: Entity> GenericMatrixMut for inner::SparseRowMat<I, E> {
408    #[inline(always)]
409    fn as_mut(this: &mut Matrix<Self>) -> <Self::Kind as MatrixKind>::Mut<'_, Self::Elem> {
410        this.as_mut()
411    }
412}
413
414mod __matmul_assign {
415    use super::*;
416
417    impl MatMulAssign<Scale> for DenseCol {
418        #[track_caller]
419        fn mat_mul_assign<E: ComplexField, RhsE: Conjugate<Canonical = E>>(
420            lhs: KindMut<'_, E, DenseCol>,
421            rhs: KindRef<'_, RhsE, Scale>,
422        ) {
423            let rhs = rhs.value().canonicalize();
424            zipped!(lhs.as_2d_mut())
425                .for_each(|unzipped!(mut lhs)| lhs.write(lhs.read().faer_mul(rhs)));
426        }
427    }
428    impl MatMulAssign<Scale> for DenseRow {
429        #[track_caller]
430        fn mat_mul_assign<E: ComplexField, RhsE: Conjugate<Canonical = E>>(
431            lhs: KindMut<'_, E, DenseRow>,
432            rhs: KindRef<'_, RhsE, Scale>,
433        ) {
434            let rhs = rhs.value().canonicalize();
435            zipped!(lhs.as_2d_mut())
436                .for_each(|unzipped!(mut lhs)| lhs.write(lhs.read().faer_mul(rhs)));
437        }
438    }
439    impl MatMulAssign<Scale> for Dense {
440        #[track_caller]
441        fn mat_mul_assign<E: ComplexField, RhsE: Conjugate<Canonical = E>>(
442            lhs: KindMut<'_, E, Dense>,
443            rhs: KindRef<'_, RhsE, Scale>,
444        ) {
445            let rhs = rhs.value().canonicalize();
446            zipped!(lhs).for_each(|unzipped!(mut lhs)| lhs.write(lhs.read().faer_mul(rhs)));
447        }
448    }
449    impl MatMulAssign<Scale> for Scale {
450        #[track_caller]
451        fn mat_mul_assign<E: ComplexField, RhsE: Conjugate<Canonical = E>>(
452            lhs: KindMut<'_, E, Scale>,
453            rhs: KindRef<'_, RhsE, Scale>,
454        ) {
455            let rhs = rhs.value().canonicalize();
456            *lhs = scale((*lhs).value().faer_mul(rhs));
457        }
458    }
459
460    impl MatMulAssign<Diag> for Diag {
461        #[track_caller]
462        fn mat_mul_assign<E: ComplexField, RhsE: Conjugate<Canonical = E>>(
463            lhs: KindMut<'_, E, Diag>,
464            rhs: KindRef<'_, RhsE, Diag>,
465        ) {
466            zipped!(lhs.inner.inner.as_2d_mut(), rhs.inner.inner.as_2d()).for_each(
467                |unzipped!(mut lhs, rhs)| lhs.write(lhs.read().faer_mul(rhs.read().canonicalize())),
468            );
469        }
470    }
471}
472
473mod __matmul {
474    use super::*;
475    use crate::{assert, permutation::Permutation};
476
477    impl<I: Index> MatMul<Perm<I>> for Perm<I> {
478        type Output = Perm<I>;
479
480        #[track_caller]
481        fn mat_mul<
482            E: ComplexField,
483            LhsE: Conjugate<Canonical = E>,
484            RhsE: Conjugate<Canonical = E>,
485        >(
486            lhs: KindRef<'_, LhsE, Perm<I>>,
487            rhs: KindRef<'_, RhsE, Perm<I>>,
488        ) -> KindOwn<E, Self::Output> {
489            assert!(lhs.len() == rhs.len());
490            let truncate = <I::Signed as SignedIndex>::truncate;
491            let mut fwd = alloc::vec![I::from_signed(truncate(0)); lhs.len()].into_boxed_slice();
492            let mut inv = alloc::vec![I::from_signed(truncate(0)); lhs.len()].into_boxed_slice();
493
494            for (fwd, rhs) in fwd.iter_mut().zip(rhs.inner.forward) {
495                *fwd = lhs.inner.forward[rhs.to_signed().zx()];
496            }
497            for (i, fwd) in fwd.iter().enumerate() {
498                inv[fwd.to_signed().zx()] = I::from_signed(I::Signed::truncate(i));
499            }
500
501            Permutation {
502                inner: inner::PermOwn {
503                    forward: fwd,
504                    inverse: inv,
505                    __marker: core::marker::PhantomData,
506                },
507            }
508        }
509    }
510
511    impl<I: Index> MatMul<DenseCol> for Perm<I> {
512        type Output = DenseCol;
513
514        #[track_caller]
515        fn mat_mul<
516            E: ComplexField,
517            LhsE: Conjugate<Canonical = E>,
518            RhsE: Conjugate<Canonical = E>,
519        >(
520            lhs: KindRef<'_, LhsE, Perm<I>>,
521            rhs: KindRef<'_, RhsE, DenseCol>,
522        ) -> KindOwn<E, Self::Output> {
523            assert!(lhs.len() == rhs.nrows());
524            let mut out = Col::zeros(rhs.nrows());
525            let fwd = lhs.inner.forward;
526            for (i, fwd) in fwd.iter().enumerate() {
527                out.write(i, rhs.read(fwd.to_signed().zx()).canonicalize());
528            }
529            out
530        }
531    }
532    impl<I: Index> MatMul<Dense> for Perm<I> {
533        type Output = Dense;
534
535        #[track_caller]
536        fn mat_mul<
537            E: ComplexField,
538            LhsE: Conjugate<Canonical = E>,
539            RhsE: Conjugate<Canonical = E>,
540        >(
541            lhs: KindRef<'_, LhsE, Perm<I>>,
542            rhs: KindRef<'_, RhsE, Dense>,
543        ) -> KindOwn<E, Self::Output> {
544            assert!(lhs.len() == rhs.nrows());
545            let mut out = Mat::zeros(rhs.nrows(), rhs.ncols());
546            let fwd = lhs.inner.forward;
547
548            for j in 0..rhs.ncols() {
549                for (i, fwd) in fwd.iter().enumerate() {
550                    out.write(i, j, rhs.read(fwd.to_signed().zx(), j).canonicalize());
551                }
552            }
553            out
554        }
555    }
556    impl<I: Index> MatMul<Perm<I>> for DenseRow {
557        type Output = DenseRow;
558
559        #[track_caller]
560        fn mat_mul<
561            E: ComplexField,
562            LhsE: Conjugate<Canonical = E>,
563            RhsE: Conjugate<Canonical = E>,
564        >(
565            lhs: KindRef<'_, LhsE, DenseRow>,
566            rhs: KindRef<'_, RhsE, Perm<I>>,
567        ) -> KindOwn<E, Self::Output> {
568            assert!(lhs.ncols() == rhs.len());
569            let mut out = Row::zeros(lhs.ncols());
570            let inv = rhs.inner.inverse;
571
572            for (j, inv) in inv.iter().enumerate() {
573                out.write(j, lhs.read(inv.to_signed().zx()).canonicalize());
574            }
575            out
576        }
577    }
578    impl<I: Index> MatMul<Perm<I>> for Dense {
579        type Output = Dense;
580
581        #[track_caller]
582        fn mat_mul<
583            E: ComplexField,
584            LhsE: Conjugate<Canonical = E>,
585            RhsE: Conjugate<Canonical = E>,
586        >(
587            lhs: KindRef<'_, LhsE, Dense>,
588            rhs: KindRef<'_, RhsE, Perm<I>>,
589        ) -> KindOwn<E, Self::Output> {
590            assert!(lhs.ncols() == rhs.len());
591            let mut out = Mat::zeros(lhs.nrows(), lhs.ncols());
592            let inv = rhs.inner.inverse;
593
594            for (j, inv) in inv.iter().enumerate() {
595                for i in 0..lhs.nrows() {
596                    out.write(i, j, lhs.read(i, inv.to_signed().zx()).canonicalize());
597                }
598            }
599            out
600        }
601    }
602
603    impl MatMul<DenseCol> for Scale {
604        type Output = DenseCol;
605
606        #[track_caller]
607        fn mat_mul<
608            E: ComplexField,
609            LhsE: Conjugate<Canonical = E>,
610            RhsE: Conjugate<Canonical = E>,
611        >(
612            lhs: KindRef<'_, LhsE, Scale>,
613            rhs: KindRef<'_, RhsE, DenseCol>,
614        ) -> KindOwn<E, Self::Output> {
615            let mut out = Col::<E>::zeros(rhs.nrows());
616            let lhs = lhs.inner.0.canonicalize();
617            zipped!(out.as_mut().as_2d_mut(), rhs.as_2d()).for_each(|unzipped!(mut out, rhs)| {
618                out.write(E::faer_mul(lhs, rhs.read().canonicalize()))
619            });
620            out
621        }
622    }
623    impl MatMul<Scale> for DenseCol {
624        type Output = DenseCol;
625
626        #[track_caller]
627        fn mat_mul<
628            E: ComplexField,
629            LhsE: Conjugate<Canonical = E>,
630            RhsE: Conjugate<Canonical = E>,
631        >(
632            lhs: KindRef<'_, LhsE, DenseCol>,
633            rhs: KindRef<'_, RhsE, Scale>,
634        ) -> KindOwn<E, Self::Output> {
635            let mut out = Col::<E>::zeros(lhs.nrows());
636            let rhs = rhs.inner.0.canonicalize();
637            zipped!(out.as_mut().as_2d_mut(), lhs.as_2d()).for_each(|unzipped!(mut out, lhs)| {
638                out.write(E::faer_mul(lhs.read().canonicalize(), rhs))
639            });
640            out
641        }
642    }
643    impl MatMul<DenseRow> for Scale {
644        type Output = DenseRow;
645
646        #[track_caller]
647        fn mat_mul<
648            E: ComplexField,
649            LhsE: Conjugate<Canonical = E>,
650            RhsE: Conjugate<Canonical = E>,
651        >(
652            lhs: KindRef<'_, LhsE, Scale>,
653            rhs: KindRef<'_, RhsE, DenseRow>,
654        ) -> KindOwn<E, Self::Output> {
655            let mut out = Row::<E>::zeros(rhs.nrows());
656            let lhs = lhs.inner.0.canonicalize();
657            zipped!(out.as_mut().as_2d_mut(), rhs.as_2d()).for_each(|unzipped!(mut out, rhs)| {
658                out.write(E::faer_mul(lhs, rhs.read().canonicalize()))
659            });
660            out
661        }
662    }
663    impl MatMul<Scale> for DenseRow {
664        type Output = DenseRow;
665
666        #[track_caller]
667        fn mat_mul<
668            E: ComplexField,
669            LhsE: Conjugate<Canonical = E>,
670            RhsE: Conjugate<Canonical = E>,
671        >(
672            lhs: KindRef<'_, LhsE, DenseRow>,
673            rhs: KindRef<'_, RhsE, Scale>,
674        ) -> KindOwn<E, Self::Output> {
675            let mut out = Row::<E>::zeros(lhs.nrows());
676            let rhs = rhs.inner.0.canonicalize();
677            zipped!(out.as_mut().as_2d_mut(), lhs.as_2d()).for_each(|unzipped!(mut out, lhs)| {
678                out.write(E::faer_mul(lhs.read().canonicalize(), rhs))
679            });
680            out
681        }
682    }
683    impl MatMul<Dense> for Scale {
684        type Output = Dense;
685
686        #[track_caller]
687        fn mat_mul<
688            E: ComplexField,
689            LhsE: Conjugate<Canonical = E>,
690            RhsE: Conjugate<Canonical = E>,
691        >(
692            lhs: KindRef<'_, LhsE, Scale>,
693            rhs: KindRef<'_, RhsE, Dense>,
694        ) -> KindOwn<E, Self::Output> {
695            let mut out = Mat::<E>::zeros(rhs.nrows(), rhs.ncols());
696            let lhs = lhs.inner.0.canonicalize();
697            zipped!(out.as_mut(), rhs).for_each(|unzipped!(mut out, rhs)| {
698                out.write(E::faer_mul(lhs, rhs.read().canonicalize()))
699            });
700            out
701        }
702    }
703    impl MatMul<Scale> for Dense {
704        type Output = Dense;
705
706        #[track_caller]
707        fn mat_mul<
708            E: ComplexField,
709            LhsE: Conjugate<Canonical = E>,
710            RhsE: Conjugate<Canonical = E>,
711        >(
712            lhs: KindRef<'_, LhsE, Dense>,
713            rhs: KindRef<'_, RhsE, Scale>,
714        ) -> KindOwn<E, Self::Output> {
715            let mut out = Mat::<E>::zeros(lhs.nrows(), lhs.ncols());
716            let rhs = rhs.inner.0.canonicalize();
717            zipped!(out.as_mut(), lhs).for_each(|unzipped!(mut out, lhs)| {
718                out.write(E::faer_mul(lhs.read().canonicalize(), rhs))
719            });
720            out
721        }
722    }
723    impl MatMul<Scale> for Scale {
724        type Output = Scale;
725
726        #[track_caller]
727        fn mat_mul<
728            E: ComplexField,
729            LhsE: Conjugate<Canonical = E>,
730            RhsE: Conjugate<Canonical = E>,
731        >(
732            lhs: KindRef<'_, LhsE, Scale>,
733            rhs: KindRef<'_, RhsE, Scale>,
734        ) -> KindOwn<E, Self::Output> {
735            scale(E::faer_mul(
736                lhs.inner.0.canonicalize(),
737                rhs.inner.0.canonicalize(),
738            ))
739        }
740    }
741
742    impl MatMul<Diag> for DenseRow {
743        type Output = DenseRow;
744
745        #[track_caller]
746        fn mat_mul<
747            E: ComplexField,
748            LhsE: Conjugate<Canonical = E>,
749            RhsE: Conjugate<Canonical = E>,
750        >(
751            lhs: KindRef<'_, LhsE, DenseRow>,
752            rhs: KindRef<'_, RhsE, Diag>,
753        ) -> KindOwn<E, Self::Output> {
754            let lhs_ncols = lhs.ncols();
755            let rhs_dim = rhs.inner.inner.nrows();
756            assert!(lhs_ncols == rhs_dim);
757
758            Row::from_fn(lhs_ncols, |j| unsafe {
759                E::faer_mul(
760                    lhs.read_unchecked(j).canonicalize(),
761                    rhs.inner.inner.read_unchecked(j).canonicalize(),
762                )
763            })
764        }
765    }
766    impl MatMul<Diag> for Dense {
767        type Output = Dense;
768
769        #[track_caller]
770        fn mat_mul<
771            E: ComplexField,
772            LhsE: Conjugate<Canonical = E>,
773            RhsE: Conjugate<Canonical = E>,
774        >(
775            lhs: KindRef<'_, LhsE, Dense>,
776            rhs: KindRef<'_, RhsE, Diag>,
777        ) -> KindOwn<E, Self::Output> {
778            let lhs_ncols = lhs.ncols();
779            let rhs_dim = rhs.inner.inner.nrows();
780            assert!(lhs_ncols == rhs_dim);
781
782            Mat::from_fn(lhs.nrows(), lhs.ncols(), |i, j| unsafe {
783                E::faer_mul(
784                    lhs.read_unchecked(i, j).canonicalize(),
785                    rhs.inner.inner.read_unchecked(j).canonicalize(),
786                )
787            })
788        }
789    }
790
791    impl MatMul<DenseCol> for Diag {
792        type Output = DenseCol;
793
794        #[track_caller]
795        fn mat_mul<
796            E: ComplexField,
797            LhsE: Conjugate<Canonical = E>,
798            RhsE: Conjugate<Canonical = E>,
799        >(
800            lhs: KindRef<'_, LhsE, Diag>,
801            rhs: KindRef<'_, RhsE, DenseCol>,
802        ) -> KindOwn<E, Self::Output> {
803            let lhs_dim = lhs.inner.inner.nrows();
804            let rhs_nrows = rhs.nrows();
805            assert!(lhs_dim == rhs_nrows);
806
807            Col::from_fn(rhs.nrows(), |i| unsafe {
808                E::faer_mul(
809                    lhs.inner.inner.read_unchecked(i).canonicalize(),
810                    rhs.read_unchecked(i).canonicalize(),
811                )
812            })
813        }
814    }
815    impl MatMul<Dense> for Diag {
816        type Output = Dense;
817
818        #[track_caller]
819        fn mat_mul<
820            E: ComplexField,
821            LhsE: Conjugate<Canonical = E>,
822            RhsE: Conjugate<Canonical = E>,
823        >(
824            lhs: KindRef<'_, LhsE, Diag>,
825            rhs: KindRef<'_, RhsE, Dense>,
826        ) -> KindOwn<E, Self::Output> {
827            let lhs_dim = lhs.inner.inner.nrows();
828            let rhs_nrows = rhs.nrows();
829            assert!(lhs_dim == rhs_nrows);
830
831            Mat::from_fn(rhs.nrows(), rhs.ncols(), |i, j| unsafe {
832                E::faer_mul(
833                    lhs.inner.inner.read_unchecked(i).canonicalize(),
834                    rhs.read_unchecked(i, j).canonicalize(),
835                )
836            })
837        }
838    }
839
840    impl MatMul<Diag> for Diag {
841        type Output = Diag;
842
843        #[track_caller]
844        fn mat_mul<
845            E: ComplexField,
846            LhsE: Conjugate<Canonical = E>,
847            RhsE: Conjugate<Canonical = E>,
848        >(
849            lhs: KindRef<'_, LhsE, Diag>,
850            rhs: KindRef<'_, RhsE, Diag>,
851        ) -> KindOwn<E, Self::Output> {
852            let lhs_dim = lhs.inner.inner.nrows();
853            let rhs_dim = rhs.inner.inner.nrows();
854            assert!(lhs_dim == rhs_dim);
855
856            Matrix {
857                inner: inner::DiagOwn {
858                    inner: Col::from_fn(lhs_dim, |i| unsafe {
859                        E::faer_mul(
860                            lhs.inner.inner.read_unchecked(i).canonicalize(),
861                            rhs.inner.inner.read_unchecked(i).canonicalize(),
862                        )
863                    }),
864                },
865            }
866        }
867    }
868
869    impl MatMul<Dense> for Dense {
870        type Output = Dense;
871
872        #[track_caller]
873        fn mat_mul<
874            E: ComplexField,
875            LhsE: Conjugate<Canonical = E>,
876            RhsE: Conjugate<Canonical = E>,
877        >(
878            lhs: KindRef<'_, LhsE, Self>,
879            rhs: KindRef<'_, RhsE, Self>,
880        ) -> KindOwn<E, Self::Output> {
881            assert!(lhs.ncols() == rhs.nrows());
882            let mut out = Mat::zeros(lhs.nrows(), rhs.ncols());
883            mul::matmul(
884                out.as_mut(),
885                lhs,
886                rhs,
887                None,
888                E::faer_one(),
889                get_global_parallelism(),
890            );
891            out
892        }
893    }
894
895    impl MatMul<DenseCol> for Dense {
896        type Output = DenseCol;
897
898        #[track_caller]
899        fn mat_mul<
900            E: ComplexField,
901            LhsE: Conjugate<Canonical = E>,
902            RhsE: Conjugate<Canonical = E>,
903        >(
904            lhs: KindRef<'_, LhsE, Dense>,
905            rhs: KindRef<'_, RhsE, DenseCol>,
906        ) -> KindOwn<E, Self::Output> {
907            assert!(lhs.ncols() == rhs.nrows());
908            let mut out = Col::zeros(lhs.nrows());
909            mul::matmul(
910                out.as_mut().as_2d_mut(),
911                lhs,
912                rhs.as_2d(),
913                None,
914                E::faer_one(),
915                get_global_parallelism(),
916            );
917            out
918        }
919    }
920    impl MatMul<Dense> for DenseRow {
921        type Output = DenseRow;
922
923        #[track_caller]
924        fn mat_mul<
925            E: ComplexField,
926            LhsE: Conjugate<Canonical = E>,
927            RhsE: Conjugate<Canonical = E>,
928        >(
929            lhs: KindRef<'_, LhsE, DenseRow>,
930            rhs: KindRef<'_, RhsE, Dense>,
931        ) -> KindOwn<E, Self::Output> {
932            assert!(lhs.ncols() == rhs.nrows());
933            let mut out = Row::zeros(lhs.nrows());
934            mul::matmul(
935                out.as_mut().as_2d_mut(),
936                lhs.as_2d(),
937                rhs,
938                None,
939                E::faer_one(),
940                get_global_parallelism(),
941            );
942            out
943        }
944    }
945
946    impl MatMul<DenseCol> for DenseRow {
947        type Output = Scalar;
948
949        #[track_caller]
950        fn mat_mul<
951            E: ComplexField,
952            LhsE: Conjugate<Canonical = E>,
953            RhsE: Conjugate<Canonical = E>,
954        >(
955            lhs: KindRef<'_, LhsE, DenseRow>,
956            rhs: KindRef<'_, RhsE, DenseCol>,
957        ) -> KindOwn<E, Self::Output> {
958            assert!(lhs.ncols() == rhs.nrows());
959            let (lhs, conj_lhs) = lhs.canonicalize();
960            let (rhs, conj_rhs) = rhs.canonicalize();
961
962            crate::mul::inner_prod::inner_prod_with_conj(
963                lhs.transpose().as_2d(),
964                conj_lhs,
965                rhs.as_2d(),
966                conj_rhs,
967            )
968        }
969    }
970
971    impl MatMul<DenseRow> for DenseCol {
972        type Output = Dense;
973
974        #[track_caller]
975        fn mat_mul<
976            E: ComplexField,
977            LhsE: Conjugate<Canonical = E>,
978            RhsE: Conjugate<Canonical = E>,
979        >(
980            lhs: KindRef<'_, LhsE, DenseCol>,
981            rhs: KindRef<'_, RhsE, DenseRow>,
982        ) -> KindOwn<E, Self::Output> {
983            assert!(lhs.ncols() == rhs.nrows());
984            let mut out = Mat::zeros(lhs.nrows(), rhs.ncols());
985            mul::matmul(
986                out.as_mut(),
987                lhs.as_2d(),
988                rhs.as_2d(),
989                None,
990                E::faer_one(),
991                get_global_parallelism(),
992            );
993            out
994        }
995    }
996
997    impl<I: Index> MatMul<SparseColMat<I>> for Dense {
998        type Output = Dense;
999
1000        #[track_caller]
1001        fn mat_mul<
1002            E: ComplexField,
1003            LhsE: Conjugate<Canonical = E>,
1004            RhsE: Conjugate<Canonical = E>,
1005        >(
1006            lhs: KindRef<'_, LhsE, Self>,
1007            rhs: KindRef<'_, RhsE, SparseColMat<I>>,
1008        ) -> KindOwn<E, Self::Output> {
1009            let mut out = Mat::zeros(lhs.nrows(), rhs.ncols());
1010            sparse::mul::dense_sparse_matmul(
1011                out.as_mut(),
1012                lhs,
1013                rhs,
1014                None,
1015                E::faer_one(),
1016                get_global_parallelism(),
1017            );
1018            out
1019        }
1020    }
1021    impl<I: Index> MatMul<SparseColMat<I>> for DenseRow {
1022        type Output = DenseRow;
1023
1024        #[track_caller]
1025        fn mat_mul<
1026            E: ComplexField,
1027            LhsE: Conjugate<Canonical = E>,
1028            RhsE: Conjugate<Canonical = E>,
1029        >(
1030            lhs: KindRef<'_, LhsE, Self>,
1031            rhs: KindRef<'_, RhsE, SparseColMat<I>>,
1032        ) -> KindOwn<E, Self::Output> {
1033            let mut out = Row::zeros(rhs.ncols());
1034            sparse::mul::dense_sparse_matmul(
1035                out.as_mut().as_2d_mut(),
1036                lhs.as_2d(),
1037                rhs,
1038                None,
1039                E::faer_one(),
1040                get_global_parallelism(),
1041            );
1042            out
1043        }
1044    }
1045    impl<I: Index> MatMul<SparseRowMat<I>> for Dense {
1046        type Output = Dense;
1047
1048        #[track_caller]
1049        fn mat_mul<
1050            E: ComplexField,
1051            LhsE: Conjugate<Canonical = E>,
1052            RhsE: Conjugate<Canonical = E>,
1053        >(
1054            lhs: KindRef<'_, LhsE, Self>,
1055            rhs: KindRef<'_, RhsE, SparseRowMat<I>>,
1056        ) -> KindOwn<E, Self::Output> {
1057            let mut out = Mat::zeros(lhs.nrows(), rhs.ncols());
1058            sparse::mul::sparse_dense_matmul(
1059                out.as_mut().transpose_mut(),
1060                rhs.transpose(),
1061                lhs.transpose(),
1062                None,
1063                E::faer_one(),
1064                get_global_parallelism(),
1065            );
1066            out
1067        }
1068    }
1069    impl<I: Index> MatMul<SparseRowMat<I>> for DenseRow {
1070        type Output = DenseRow;
1071
1072        #[track_caller]
1073        fn mat_mul<
1074            E: ComplexField,
1075            LhsE: Conjugate<Canonical = E>,
1076            RhsE: Conjugate<Canonical = E>,
1077        >(
1078            lhs: KindRef<'_, LhsE, Self>,
1079            rhs: KindRef<'_, RhsE, SparseRowMat<I>>,
1080        ) -> KindOwn<E, Self::Output> {
1081            let mut out = Row::zeros(rhs.ncols());
1082            sparse::mul::sparse_dense_matmul(
1083                out.as_mut().transpose_mut().as_2d_mut(),
1084                rhs.transpose(),
1085                lhs.transpose().as_2d(),
1086                None,
1087                E::faer_one(),
1088                get_global_parallelism(),
1089            );
1090            out
1091        }
1092    }
1093
1094    impl<I: Index> MatMul<Dense> for SparseColMat<I> {
1095        type Output = Dense;
1096
1097        #[track_caller]
1098        fn mat_mul<
1099            E: ComplexField,
1100            LhsE: Conjugate<Canonical = E>,
1101            RhsE: Conjugate<Canonical = E>,
1102        >(
1103            lhs: KindRef<'_, LhsE, Self>,
1104            rhs: KindRef<'_, RhsE, Dense>,
1105        ) -> KindOwn<E, Self::Output> {
1106            let mut out = Mat::zeros(lhs.nrows(), rhs.ncols());
1107            sparse::mul::sparse_dense_matmul(
1108                out.as_mut(),
1109                lhs,
1110                rhs,
1111                None,
1112                E::faer_one(),
1113                get_global_parallelism(),
1114            );
1115            out
1116        }
1117    }
1118    impl<I: Index> MatMul<DenseCol> for SparseColMat<I> {
1119        type Output = DenseCol;
1120
1121        #[track_caller]
1122        fn mat_mul<
1123            E: ComplexField,
1124            LhsE: Conjugate<Canonical = E>,
1125            RhsE: Conjugate<Canonical = E>,
1126        >(
1127            lhs: KindRef<'_, LhsE, Self>,
1128            rhs: KindRef<'_, RhsE, DenseCol>,
1129        ) -> KindOwn<E, Self::Output> {
1130            let mut out = Col::zeros(lhs.nrows());
1131            sparse::mul::sparse_dense_matmul(
1132                out.as_mut().as_2d_mut(),
1133                lhs,
1134                rhs.as_2d(),
1135                None,
1136                E::faer_one(),
1137                get_global_parallelism(),
1138            );
1139            out
1140        }
1141    }
1142    impl<I: Index> MatMul<Dense> for SparseRowMat<I> {
1143        type Output = Dense;
1144
1145        #[track_caller]
1146        fn mat_mul<
1147            E: ComplexField,
1148            LhsE: Conjugate<Canonical = E>,
1149            RhsE: Conjugate<Canonical = E>,
1150        >(
1151            lhs: KindRef<'_, LhsE, Self>,
1152            rhs: KindRef<'_, RhsE, Dense>,
1153        ) -> KindOwn<E, Self::Output> {
1154            let mut out = Mat::zeros(lhs.nrows(), rhs.ncols());
1155            sparse::mul::dense_sparse_matmul(
1156                out.as_mut().transpose_mut(),
1157                rhs.transpose(),
1158                lhs.transpose(),
1159                None,
1160                E::faer_one(),
1161                get_global_parallelism(),
1162            );
1163            out
1164        }
1165    }
1166    impl<I: Index> MatMul<DenseCol> for SparseRowMat<I> {
1167        type Output = DenseCol;
1168
1169        #[track_caller]
1170        fn mat_mul<
1171            E: ComplexField,
1172            LhsE: Conjugate<Canonical = E>,
1173            RhsE: Conjugate<Canonical = E>,
1174        >(
1175            lhs: KindRef<'_, LhsE, Self>,
1176            rhs: KindRef<'_, RhsE, DenseCol>,
1177        ) -> KindOwn<E, Self::Output> {
1178            let mut out = Col::zeros(lhs.nrows());
1179            sparse::mul::dense_sparse_matmul(
1180                out.as_mut().transpose_mut().as_2d_mut(),
1181                rhs.transpose().as_2d(),
1182                lhs.transpose(),
1183                None,
1184                E::faer_one(),
1185                get_global_parallelism(),
1186            );
1187            out
1188        }
1189    }
1190}
1191
1192/// Matrix multiplication.
1193pub trait MatMulAssign<Rhs: MatrixKind>: MatrixKind {
1194    /// Computes `lhs * rhs` and assigns it to `lhs`.
1195    fn mat_mul_assign<E: ComplexField, RhsE: Conjugate<Canonical = E>>(
1196        lhs: KindMut<'_, E, Self>,
1197        rhs: KindRef<'_, RhsE, Rhs>,
1198    );
1199}
1200/// Matrix addition.
1201pub trait MatAddAssign<Rhs: MatrixKind>: MatrixKind {
1202    /// Computes `lhs + rhs` and assigns it to `lhs`.
1203    fn mat_add_assign<E: ComplexField, RhsE: Conjugate<Canonical = E>>(
1204        lhs: KindMut<'_, E, Self>,
1205        rhs: KindRef<'_, RhsE, Rhs>,
1206    );
1207}
1208/// Matrix subtraction.
1209pub trait MatSubAssign<Rhs: MatrixKind>: MatrixKind {
1210    /// Computes `lhs - rhs` and assigns it to `lhs`.
1211    fn mat_sub_assign<E: ComplexField, RhsE: Conjugate<Canonical = E>>(
1212        lhs: KindMut<'_, E, Self>,
1213        rhs: KindRef<'_, RhsE, Rhs>,
1214    );
1215}
1216
1217/// Matrix equality comparison.
1218pub trait MatEq<Rhs: MatrixKind>: MatrixKind {
1219    /// Computes `lhs == rhs`.
1220    fn mat_eq<E: ComplexField, LhsE: Conjugate<Canonical = E>, RhsE: Conjugate<Canonical = E>>(
1221        lhs: KindRef<'_, LhsE, Self>,
1222        rhs: KindRef<'_, RhsE, Rhs>,
1223    ) -> bool;
1224}
1225
1226/// Matrix multiplication.
1227pub trait MatMul<Rhs: MatrixKind>: MatrixKind {
1228    /// Result matrix type.
1229    type Output: MatrixKind;
1230
1231    /// Returns `lhs * rhs`.
1232    fn mat_mul<E: ComplexField, LhsE: Conjugate<Canonical = E>, RhsE: Conjugate<Canonical = E>>(
1233        lhs: KindRef<'_, LhsE, Self>,
1234        rhs: KindRef<'_, RhsE, Rhs>,
1235    ) -> KindOwn<E, Self::Output>;
1236}
1237/// Matrix addition.
1238pub trait MatAdd<Rhs: MatrixKind>: MatrixKind {
1239    /// Result matrix type.
1240    type Output: MatrixKind;
1241
1242    /// Returns `lhs + rhs`.
1243    fn mat_add<E: ComplexField, LhsE: Conjugate<Canonical = E>, RhsE: Conjugate<Canonical = E>>(
1244        lhs: KindRef<'_, LhsE, Self>,
1245        rhs: KindRef<'_, RhsE, Rhs>,
1246    ) -> KindOwn<E, Self::Output>;
1247}
1248/// Matrix subtraction.
1249pub trait MatSub<Rhs: MatrixKind>: MatrixKind {
1250    /// Result matrix type.
1251    type Output: MatrixKind;
1252
1253    /// Returns `lhs - rhs`.
1254    fn mat_sub<E: ComplexField, LhsE: Conjugate<Canonical = E>, RhsE: Conjugate<Canonical = E>>(
1255        lhs: KindRef<'_, LhsE, Self>,
1256        rhs: KindRef<'_, RhsE, Rhs>,
1257    ) -> KindOwn<E, Self::Output>;
1258}
1259/// Matrix negation.
1260pub trait MatNeg: MatrixKind {
1261    /// Result matrix type.
1262    type Output: MatrixKind;
1263
1264    /// Returns `-mat`.
1265    fn mat_neg<E: Conjugate>(mat: KindRef<'_, E, Self>) -> KindOwn<E::Canonical, Self::Output>
1266    where
1267        E::Canonical: ComplexField;
1268}
1269
1270impl<I: Index> MatEq<Perm<I>> for Perm<I> {
1271    #[track_caller]
1272    fn mat_eq<E: ComplexField, LhsE: Conjugate<Canonical = E>, RhsE: Conjugate<Canonical = E>>(
1273        lhs: KindRef<'_, LhsE, Self>,
1274        rhs: KindRef<'_, RhsE, Self>,
1275    ) -> bool {
1276        lhs.inner.forward == rhs.inner.forward
1277    }
1278}
1279
1280impl MatEq<DenseCol> for DenseCol {
1281    #[track_caller]
1282    fn mat_eq<E: ComplexField, LhsE: Conjugate<Canonical = E>, RhsE: Conjugate<Canonical = E>>(
1283        lhs: KindRef<'_, LhsE, Self>,
1284        rhs: KindRef<'_, RhsE, Self>,
1285    ) -> bool {
1286        lhs.as_2d() == rhs.as_2d()
1287    }
1288}
1289impl MatEq<DenseRow> for DenseRow {
1290    #[track_caller]
1291    fn mat_eq<E: ComplexField, LhsE: Conjugate<Canonical = E>, RhsE: Conjugate<Canonical = E>>(
1292        lhs: KindRef<'_, LhsE, Self>,
1293        rhs: KindRef<'_, RhsE, Self>,
1294    ) -> bool {
1295        lhs.as_2d() == rhs.as_2d()
1296    }
1297}
1298
1299impl MatEq<Dense> for Dense {
1300    #[track_caller]
1301    fn mat_eq<E: ComplexField, LhsE: Conjugate<Canonical = E>, RhsE: Conjugate<Canonical = E>>(
1302        lhs: KindRef<'_, LhsE, Self>,
1303        rhs: KindRef<'_, RhsE, Self>,
1304    ) -> bool {
1305        if (lhs.nrows(), lhs.ncols()) != (rhs.nrows(), rhs.ncols()) {
1306            return false;
1307        }
1308        let m = lhs.nrows();
1309        let n = lhs.ncols();
1310        for j in 0..n {
1311            for i in 0..m {
1312                if !(lhs.read(i, j).canonicalize() == rhs.read(i, j).canonicalize()) {
1313                    return false;
1314                }
1315            }
1316        }
1317
1318        true
1319    }
1320}
1321
1322impl<I: Index> MatEq<SparseColMat<I>> for SparseColMat<I> {
1323    fn mat_eq<E: ComplexField, LhsE: Conjugate<Canonical = E>, RhsE: Conjugate<Canonical = E>>(
1324        lhs: KindRef<'_, LhsE, Self>,
1325        rhs: KindRef<'_, RhsE, Self>,
1326    ) -> bool {
1327        if lhs.nrows() != rhs.nrows() || lhs.ncols() != rhs.ncols() {
1328            return false;
1329        }
1330
1331        let n = lhs.ncols();
1332        let mut equal = true;
1333        for j in 0..n {
1334            equal &= lhs.row_indices_of_col_raw(j) == rhs.row_indices_of_col_raw(j);
1335            let lhs_val = SliceGroup::<'_, LhsE>::new(lhs.values_of_col(j));
1336            let rhs_val = SliceGroup::<'_, RhsE>::new(rhs.values_of_col(j));
1337            equal &= lhs_val
1338                .into_ref_iter()
1339                .map(|r| r.read().canonicalize())
1340                .eq(rhs_val.into_ref_iter().map(|r| r.read().canonicalize()))
1341        }
1342
1343        equal
1344    }
1345}
1346
1347impl<I: Index> MatEq<SparseRowMat<I>> for SparseRowMat<I> {
1348    fn mat_eq<E: ComplexField, LhsE: Conjugate<Canonical = E>, RhsE: Conjugate<Canonical = E>>(
1349        lhs: KindRef<'_, LhsE, Self>,
1350        rhs: KindRef<'_, RhsE, Self>,
1351    ) -> bool {
1352        lhs.transpose() == rhs.transpose()
1353    }
1354}
1355
1356impl MatAdd<DenseCol> for DenseCol {
1357    type Output = DenseCol;
1358
1359    #[track_caller]
1360    fn mat_add<E: ComplexField, LhsE: Conjugate<Canonical = E>, RhsE: Conjugate<Canonical = E>>(
1361        lhs: KindRef<'_, LhsE, Self>,
1362        rhs: KindRef<'_, RhsE, Self>,
1363    ) -> KindOwn<E, Self::Output> {
1364        assert!(all(lhs.nrows() == rhs.nrows(), lhs.ncols() == rhs.ncols()));
1365        let mut out = Col::<E>::zeros(lhs.nrows());
1366        zipped!(out.as_mut().as_2d_mut(), lhs.as_2d(), rhs.as_2d()).for_each(
1367            |unzipped!(mut out, lhs, rhs)| {
1368                out.write(E::faer_add(
1369                    lhs.read().canonicalize(),
1370                    rhs.read().canonicalize(),
1371                ))
1372            },
1373        );
1374        out
1375    }
1376}
1377impl MatSub<DenseCol> for DenseCol {
1378    type Output = DenseCol;
1379
1380    #[track_caller]
1381    fn mat_sub<E: ComplexField, LhsE: Conjugate<Canonical = E>, RhsE: Conjugate<Canonical = E>>(
1382        lhs: KindRef<'_, LhsE, Self>,
1383        rhs: KindRef<'_, RhsE, Self>,
1384    ) -> KindOwn<E, Self::Output> {
1385        assert!(all(lhs.nrows() == rhs.nrows(), lhs.ncols() == rhs.ncols()));
1386        let mut out = Col::<E>::zeros(lhs.nrows());
1387        zipped!(out.as_mut().as_2d_mut(), lhs.as_2d(), rhs.as_2d()).for_each(
1388            |unzipped!(mut out, lhs, rhs)| {
1389                out.write(E::faer_sub(
1390                    lhs.read().canonicalize(),
1391                    rhs.read().canonicalize(),
1392                ))
1393            },
1394        );
1395        out
1396    }
1397}
1398impl MatAddAssign<DenseCol> for DenseCol {
1399    #[track_caller]
1400    fn mat_add_assign<E: ComplexField, RhsE: Conjugate<Canonical = E>>(
1401        lhs: KindMut<'_, E, DenseCol>,
1402        rhs: KindRef<'_, RhsE, DenseCol>,
1403    ) {
1404        zipped!(lhs.as_2d_mut(), rhs.as_2d()).for_each(|unzipped!(mut lhs, rhs)| {
1405            lhs.write(lhs.read().faer_add(rhs.read().canonicalize()))
1406        });
1407    }
1408}
1409impl MatSubAssign<DenseCol> for DenseCol {
1410    #[track_caller]
1411    fn mat_sub_assign<E: ComplexField, RhsE: Conjugate<Canonical = E>>(
1412        lhs: KindMut<'_, E, DenseCol>,
1413        rhs: KindRef<'_, RhsE, DenseCol>,
1414    ) {
1415        zipped!(lhs.as_2d_mut(), rhs.as_2d()).for_each(|unzipped!(mut lhs, rhs)| {
1416            lhs.write(lhs.read().faer_sub(rhs.read().canonicalize()))
1417        });
1418    }
1419}
1420
1421impl MatNeg for DenseCol {
1422    type Output = DenseCol;
1423
1424    fn mat_neg<E: Conjugate>(mat: KindRef<'_, E, Self>) -> KindOwn<E::Canonical, Self::Output>
1425    where
1426        E::Canonical: ComplexField,
1427    {
1428        let mut out = Col::<E::Canonical>::zeros(mat.nrows());
1429        zipped!(out.as_mut().as_2d_mut(), mat.as_2d())
1430            .for_each(|unzipped!(mut out, src)| out.write(src.read().canonicalize().faer_neg()));
1431        out
1432    }
1433}
1434
1435impl MatAdd<DenseRow> for DenseRow {
1436    type Output = DenseRow;
1437
1438    #[track_caller]
1439    fn mat_add<E: ComplexField, LhsE: Conjugate<Canonical = E>, RhsE: Conjugate<Canonical = E>>(
1440        lhs: KindRef<'_, LhsE, Self>,
1441        rhs: KindRef<'_, RhsE, Self>,
1442    ) -> KindOwn<E, Self::Output> {
1443        assert!(all(lhs.nrows() == rhs.nrows(), lhs.ncols() == rhs.ncols()));
1444        let mut out = Row::<E>::zeros(lhs.nrows());
1445        zipped!(out.as_mut().as_2d_mut(), lhs.as_2d(), rhs.as_2d()).for_each(
1446            |unzipped!(mut out, lhs, rhs)| {
1447                out.write(E::faer_add(
1448                    lhs.read().canonicalize(),
1449                    rhs.read().canonicalize(),
1450                ))
1451            },
1452        );
1453        out
1454    }
1455}
1456impl MatSub<DenseRow> for DenseRow {
1457    type Output = DenseRow;
1458
1459    #[track_caller]
1460    fn mat_sub<E: ComplexField, LhsE: Conjugate<Canonical = E>, RhsE: Conjugate<Canonical = E>>(
1461        lhs: KindRef<'_, LhsE, Self>,
1462        rhs: KindRef<'_, RhsE, Self>,
1463    ) -> KindOwn<E, Self::Output> {
1464        assert!(all(lhs.nrows() == rhs.nrows(), lhs.ncols() == rhs.ncols()));
1465        let mut out = Row::<E>::zeros(lhs.nrows());
1466        zipped!(out.as_mut().as_2d_mut(), lhs.as_2d(), rhs.as_2d()).for_each(
1467            |unzipped!(mut out, lhs, rhs)| {
1468                out.write(E::faer_sub(
1469                    lhs.read().canonicalize(),
1470                    rhs.read().canonicalize(),
1471                ))
1472            },
1473        );
1474        out
1475    }
1476}
1477impl MatAddAssign<DenseRow> for DenseRow {
1478    #[track_caller]
1479    fn mat_add_assign<E: ComplexField, RhsE: Conjugate<Canonical = E>>(
1480        lhs: KindMut<'_, E, DenseRow>,
1481        rhs: KindRef<'_, RhsE, DenseRow>,
1482    ) {
1483        zipped!(lhs.as_2d_mut(), rhs.as_2d()).for_each(|unzipped!(mut lhs, rhs)| {
1484            lhs.write(lhs.read().faer_add(rhs.read().canonicalize()))
1485        });
1486    }
1487}
1488impl MatSubAssign<DenseRow> for DenseRow {
1489    #[track_caller]
1490    fn mat_sub_assign<E: ComplexField, RhsE: Conjugate<Canonical = E>>(
1491        lhs: KindMut<'_, E, DenseRow>,
1492        rhs: KindRef<'_, RhsE, DenseRow>,
1493    ) {
1494        zipped!(lhs.as_2d_mut(), rhs.as_2d()).for_each(|unzipped!(mut lhs, rhs)| {
1495            lhs.write(lhs.read().faer_sub(rhs.read().canonicalize()))
1496        });
1497    }
1498}
1499
1500impl MatNeg for DenseRow {
1501    type Output = DenseRow;
1502
1503    fn mat_neg<E: Conjugate>(mat: KindRef<'_, E, Self>) -> KindOwn<E::Canonical, Self::Output>
1504    where
1505        E::Canonical: ComplexField,
1506    {
1507        let mut out = Row::<E::Canonical>::zeros(mat.nrows());
1508        zipped!(out.as_mut().as_2d_mut(), mat.as_2d())
1509            .for_each(|unzipped!(mut out, src)| out.write(src.read().canonicalize().faer_neg()));
1510        out
1511    }
1512}
1513
1514impl MatAdd<Dense> for Dense {
1515    type Output = Dense;
1516
1517    #[track_caller]
1518    fn mat_add<E: ComplexField, LhsE: Conjugate<Canonical = E>, RhsE: Conjugate<Canonical = E>>(
1519        lhs: KindRef<'_, LhsE, Self>,
1520        rhs: KindRef<'_, RhsE, Self>,
1521    ) -> KindOwn<E, Self::Output> {
1522        assert!(all(lhs.nrows() == rhs.nrows(), lhs.ncols() == rhs.ncols()));
1523        let mut out = Mat::<E>::zeros(lhs.nrows(), rhs.ncols());
1524        zipped!(out.as_mut(), lhs, rhs).for_each(|unzipped!(mut out, lhs, rhs)| {
1525            out.write(E::faer_add(
1526                lhs.read().canonicalize(),
1527                rhs.read().canonicalize(),
1528            ))
1529        });
1530        out
1531    }
1532}
1533impl MatSub<Dense> for Dense {
1534    type Output = Dense;
1535
1536    #[track_caller]
1537    fn mat_sub<E: ComplexField, LhsE: Conjugate<Canonical = E>, RhsE: Conjugate<Canonical = E>>(
1538        lhs: KindRef<'_, LhsE, Self>,
1539        rhs: KindRef<'_, RhsE, Self>,
1540    ) -> KindOwn<E, Self::Output> {
1541        assert!(all(lhs.nrows() == rhs.nrows(), lhs.ncols() == rhs.ncols()));
1542        let mut out = Mat::<E>::zeros(lhs.nrows(), rhs.ncols());
1543        zipped!(out.as_mut(), lhs, rhs).for_each(|unzipped!(mut out, lhs, rhs)| {
1544            out.write(E::faer_sub(
1545                lhs.read().canonicalize(),
1546                rhs.read().canonicalize(),
1547            ))
1548        });
1549        out
1550    }
1551}
1552impl MatAddAssign<Dense> for Dense {
1553    #[track_caller]
1554    fn mat_add_assign<E: ComplexField, RhsE: Conjugate<Canonical = E>>(
1555        lhs: KindMut<'_, E, Dense>,
1556        rhs: KindRef<'_, RhsE, Dense>,
1557    ) {
1558        zipped!(lhs, rhs).for_each(|unzipped!(mut lhs, rhs)| {
1559            lhs.write(lhs.read().faer_add(rhs.read().canonicalize()))
1560        });
1561    }
1562}
1563impl MatSubAssign<Dense> for Dense {
1564    #[track_caller]
1565    fn mat_sub_assign<E: ComplexField, RhsE: Conjugate<Canonical = E>>(
1566        lhs: KindMut<'_, E, Dense>,
1567        rhs: KindRef<'_, RhsE, Dense>,
1568    ) {
1569        zipped!(lhs, rhs).for_each(|unzipped!(mut lhs, rhs)| {
1570            lhs.write(lhs.read().faer_sub(rhs.read().canonicalize()))
1571        });
1572    }
1573}
1574
1575impl MatNeg for Dense {
1576    type Output = Dense;
1577
1578    fn mat_neg<E: Conjugate>(mat: KindRef<'_, E, Self>) -> KindOwn<E::Canonical, Self::Output>
1579    where
1580        E::Canonical: ComplexField,
1581    {
1582        let mut out = Mat::<E::Canonical>::zeros(mat.nrows(), mat.ncols());
1583        zipped!(out.as_mut(), mat)
1584            .for_each(|unzipped!(mut out, src)| out.write(src.read().canonicalize().faer_neg()));
1585        out
1586    }
1587}
1588
1589impl<I: Index> MatAdd<SparseColMat<I>> for SparseColMat<I> {
1590    type Output = SparseColMat<I>;
1591
1592    #[track_caller]
1593    fn mat_add<E: ComplexField, LhsE: Conjugate<Canonical = E>, RhsE: Conjugate<Canonical = E>>(
1594        lhs: KindRef<'_, LhsE, Self>,
1595        rhs: KindRef<'_, RhsE, Self>,
1596    ) -> KindOwn<E, Self::Output> {
1597        crate::sparse::ops::add(lhs, rhs).unwrap()
1598    }
1599}
1600impl<I: Index> MatAdd<SparseRowMat<I>> for SparseRowMat<I> {
1601    type Output = SparseColMat<I>;
1602
1603    #[track_caller]
1604    fn mat_add<E: ComplexField, LhsE: Conjugate<Canonical = E>, RhsE: Conjugate<Canonical = E>>(
1605        lhs: KindRef<'_, LhsE, Self>,
1606        rhs: KindRef<'_, RhsE, Self>,
1607    ) -> KindOwn<E, Self::Output> {
1608        crate::sparse::ops::add(lhs.transpose(), rhs.transpose())
1609            .unwrap()
1610            .into_transpose()
1611            .to_col_major()
1612            .unwrap()
1613    }
1614}
1615impl<I: Index> MatAdd<SparseRowMat<I>> for SparseColMat<I> {
1616    type Output = SparseColMat<I>;
1617
1618    #[track_caller]
1619    fn mat_add<E: ComplexField, LhsE: Conjugate<Canonical = E>, RhsE: Conjugate<Canonical = E>>(
1620        lhs: KindRef<'_, LhsE, Self>,
1621        rhs: KindRef<'_, RhsE, SparseRowMat<I>>,
1622    ) -> KindOwn<E, Self::Output> {
1623        crate::sparse::ops::add(lhs, rhs.to_col_major().unwrap().as_ref()).unwrap()
1624    }
1625}
1626impl<I: Index> MatAdd<SparseColMat<I>> for SparseRowMat<I> {
1627    type Output = SparseColMat<I>;
1628
1629    #[track_caller]
1630    fn mat_add<E: ComplexField, LhsE: Conjugate<Canonical = E>, RhsE: Conjugate<Canonical = E>>(
1631        lhs: KindRef<'_, LhsE, Self>,
1632        rhs: KindRef<'_, RhsE, SparseColMat<I>>,
1633    ) -> KindOwn<E, Self::Output> {
1634        crate::sparse::ops::add(lhs.to_col_major().unwrap().as_ref(), rhs).unwrap()
1635    }
1636}
1637
1638impl<I: Index> MatSub<SparseColMat<I>> for SparseColMat<I> {
1639    type Output = SparseColMat<I>;
1640
1641    #[track_caller]
1642    fn mat_sub<E: ComplexField, LhsE: Conjugate<Canonical = E>, RhsE: Conjugate<Canonical = E>>(
1643        lhs: KindRef<'_, LhsE, Self>,
1644        rhs: KindRef<'_, RhsE, Self>,
1645    ) -> KindOwn<E, Self::Output> {
1646        crate::sparse::ops::sub(lhs, rhs).unwrap()
1647    }
1648}
1649impl<I: Index> MatSub<SparseRowMat<I>> for SparseRowMat<I> {
1650    type Output = SparseColMat<I>;
1651
1652    #[track_caller]
1653    fn mat_sub<E: ComplexField, LhsE: Conjugate<Canonical = E>, RhsE: Conjugate<Canonical = E>>(
1654        lhs: KindRef<'_, LhsE, Self>,
1655        rhs: KindRef<'_, RhsE, Self>,
1656    ) -> KindOwn<E, Self::Output> {
1657        crate::sparse::ops::sub(lhs.transpose(), rhs.transpose())
1658            .unwrap()
1659            .into_transpose()
1660            .to_col_major()
1661            .unwrap()
1662    }
1663}
1664impl<I: Index> MatSub<SparseRowMat<I>> for SparseColMat<I> {
1665    type Output = SparseColMat<I>;
1666
1667    #[track_caller]
1668    fn mat_sub<E: ComplexField, LhsE: Conjugate<Canonical = E>, RhsE: Conjugate<Canonical = E>>(
1669        lhs: KindRef<'_, LhsE, Self>,
1670        rhs: KindRef<'_, RhsE, SparseRowMat<I>>,
1671    ) -> KindOwn<E, Self::Output> {
1672        crate::sparse::ops::sub(lhs, rhs.to_col_major().unwrap().as_ref()).unwrap()
1673    }
1674}
1675impl<I: Index> MatSub<SparseColMat<I>> for SparseRowMat<I> {
1676    type Output = SparseColMat<I>;
1677
1678    #[track_caller]
1679    fn mat_sub<E: ComplexField, LhsE: Conjugate<Canonical = E>, RhsE: Conjugate<Canonical = E>>(
1680        lhs: KindRef<'_, LhsE, Self>,
1681        rhs: KindRef<'_, RhsE, SparseColMat<I>>,
1682    ) -> KindOwn<E, Self::Output> {
1683        crate::sparse::ops::sub(lhs.to_col_major().unwrap().as_ref(), rhs).unwrap()
1684    }
1685}
1686
1687impl<I: Index> MatNeg for SparseColMat<I> {
1688    type Output = SparseColMat<I>;
1689
1690    fn mat_neg<E: Conjugate>(mat: KindRef<'_, E, Self>) -> KindOwn<E::Canonical, Self::Output>
1691    where
1692        E::Canonical: ComplexField,
1693    {
1694        let mut out = mat.to_owned().unwrap();
1695        crate::group_helpers::SliceGroupMut::<E::Canonical>::new(out.as_mut().values_mut())
1696            .into_mut_iter()
1697            .for_each(|mut x| x.write(x.read().faer_neg()));
1698        out
1699    }
1700}
1701
1702impl<I: Index> MatNeg for SparseRowMat<I> {
1703    type Output = SparseColMat<I>;
1704
1705    fn mat_neg<E: Conjugate>(mat: KindRef<'_, E, Self>) -> KindOwn<E::Canonical, Self::Output>
1706    where
1707        E::Canonical: ComplexField,
1708    {
1709        let mut out = mat.to_col_major().unwrap();
1710        crate::group_helpers::SliceGroupMut::<E::Canonical>::new(out.as_mut().values_mut())
1711            .into_mut_iter()
1712            .for_each(|mut x| x.write(x.read().faer_neg()));
1713        out
1714    }
1715}
1716
1717impl<I: Index> MatAddAssign<SparseColMat<I>> for SparseColMat<I> {
1718    #[track_caller]
1719    fn mat_add_assign<E: ComplexField, RhsE: Conjugate<Canonical = E>>(
1720        lhs: KindMut<'_, E, SparseColMat<I>>,
1721        rhs: KindRef<'_, RhsE, SparseColMat<I>>,
1722    ) {
1723        crate::sparse::ops::add_assign(lhs, rhs);
1724    }
1725}
1726impl<I: Index> MatSubAssign<SparseColMat<I>> for SparseColMat<I> {
1727    #[track_caller]
1728    fn mat_sub_assign<E: ComplexField, RhsE: Conjugate<Canonical = E>>(
1729        lhs: KindMut<'_, E, SparseColMat<I>>,
1730        rhs: KindRef<'_, RhsE, SparseColMat<I>>,
1731    ) {
1732        crate::sparse::ops::sub_assign(lhs, rhs);
1733    }
1734}
1735
1736impl<I: Index> MatAddAssign<SparseRowMat<I>> for SparseRowMat<I> {
1737    #[track_caller]
1738    fn mat_add_assign<E: ComplexField, RhsE: Conjugate<Canonical = E>>(
1739        lhs: KindMut<'_, E, SparseRowMat<I>>,
1740        rhs: KindRef<'_, RhsE, SparseRowMat<I>>,
1741    ) {
1742        crate::sparse::ops::add_assign(lhs.transpose_mut(), rhs.transpose());
1743    }
1744}
1745impl<I: Index> MatSubAssign<SparseRowMat<I>> for SparseRowMat<I> {
1746    #[track_caller]
1747    fn mat_sub_assign<E: ComplexField, RhsE: Conjugate<Canonical = E>>(
1748        lhs: KindMut<'_, E, SparseRowMat<I>>,
1749        rhs: KindRef<'_, RhsE, SparseRowMat<I>>,
1750    ) {
1751        crate::sparse::ops::sub_assign(lhs.transpose_mut(), rhs.transpose());
1752    }
1753}
1754
1755impl<I: Index> MatAddAssign<SparseColMat<I>> for SparseRowMat<I> {
1756    #[track_caller]
1757    fn mat_add_assign<E: ComplexField, RhsE: Conjugate<Canonical = E>>(
1758        lhs: KindMut<'_, E, SparseRowMat<I>>,
1759        rhs: KindRef<'_, RhsE, SparseColMat<I>>,
1760    ) {
1761        crate::sparse::ops::add_assign(
1762            lhs.transpose_mut(),
1763            rhs.transpose().to_col_major().unwrap().as_ref(),
1764        );
1765    }
1766}
1767impl<I: Index> MatSubAssign<SparseColMat<I>> for SparseRowMat<I> {
1768    #[track_caller]
1769    fn mat_sub_assign<E: ComplexField, RhsE: Conjugate<Canonical = E>>(
1770        lhs: KindMut<'_, E, SparseRowMat<I>>,
1771        rhs: KindRef<'_, RhsE, SparseColMat<I>>,
1772    ) {
1773        crate::sparse::ops::sub_assign(
1774            lhs.transpose_mut(),
1775            rhs.transpose().to_col_major().unwrap().as_ref(),
1776        );
1777    }
1778}
1779
1780impl<I: Index> MatAddAssign<SparseRowMat<I>> for SparseColMat<I> {
1781    #[track_caller]
1782    fn mat_add_assign<E: ComplexField, RhsE: Conjugate<Canonical = E>>(
1783        lhs: KindMut<'_, E, SparseColMat<I>>,
1784        rhs: KindRef<'_, RhsE, SparseRowMat<I>>,
1785    ) {
1786        crate::sparse::ops::add_assign(lhs, rhs.to_col_major().unwrap().as_ref());
1787    }
1788}
1789impl<I: Index> MatSubAssign<SparseRowMat<I>> for SparseColMat<I> {
1790    #[track_caller]
1791    fn mat_sub_assign<E: ComplexField, RhsE: Conjugate<Canonical = E>>(
1792        lhs: KindMut<'_, E, SparseColMat<I>>,
1793        rhs: KindRef<'_, RhsE, SparseRowMat<I>>,
1794    ) {
1795        crate::sparse::ops::sub_assign(lhs, rhs.to_col_major().unwrap().as_ref());
1796    }
1797}
1798
1799/// Returns a scaling factor with the given value.
1800#[inline(always)]
1801pub fn scale<E: Entity>(value: E) -> Matrix<inner::Scale<E>> {
1802    Matrix {
1803        inner: inner::Scale(value),
1804    }
1805}
1806
1807const _: () = {
1808    use core::ops::{Add, AddAssign, Mul, MulAssign, Neg, Sub, SubAssign};
1809
1810    impl<Lhs: GenericMatrix, Rhs: GenericMatrix> Mul<&Matrix<Rhs>> for &Matrix<Lhs>
1811    where
1812        Lhs::Elem: Conjugate,
1813        Rhs::Elem: Conjugate<Canonical = <Lhs::Elem as Conjugate>::Canonical>,
1814        <Lhs::Elem as Conjugate>::Canonical: ComplexField,
1815        Lhs::Kind: MatMul<Rhs::Kind>,
1816    {
1817        type Output =
1818            KindOwn<<Lhs::Elem as Conjugate>::Canonical, <Lhs::Kind as MatMul<Rhs::Kind>>::Output>;
1819
1820        #[track_caller]
1821        fn mul(self, rhs: &Matrix<Rhs>) -> Self::Output {
1822            <Lhs::Kind as MatMul<Rhs::Kind>>::mat_mul(
1823                GenericMatrix::as_ref(self),
1824                GenericMatrix::as_ref(rhs),
1825            )
1826        }
1827    }
1828    impl<Lhs: GenericMatrix, Rhs: GenericMatrix> Mul<&Matrix<Rhs>> for Matrix<Lhs>
1829    where
1830        Lhs::Elem: Conjugate,
1831        Rhs::Elem: Conjugate<Canonical = <Lhs::Elem as Conjugate>::Canonical>,
1832        <Lhs::Elem as Conjugate>::Canonical: ComplexField,
1833        Lhs::Kind: MatMul<Rhs::Kind>,
1834    {
1835        type Output =
1836            KindOwn<<Lhs::Elem as Conjugate>::Canonical, <Lhs::Kind as MatMul<Rhs::Kind>>::Output>;
1837
1838        #[track_caller]
1839        fn mul(self, rhs: &Matrix<Rhs>) -> Self::Output {
1840            &self * rhs
1841        }
1842    }
1843    impl<Lhs: GenericMatrix, Rhs: GenericMatrix> Mul<Matrix<Rhs>> for &Matrix<Lhs>
1844    where
1845        Lhs::Elem: Conjugate,
1846        Rhs::Elem: Conjugate<Canonical = <Lhs::Elem as Conjugate>::Canonical>,
1847        <Lhs::Elem as Conjugate>::Canonical: ComplexField,
1848        Lhs::Kind: MatMul<Rhs::Kind>,
1849    {
1850        type Output =
1851            KindOwn<<Lhs::Elem as Conjugate>::Canonical, <Lhs::Kind as MatMul<Rhs::Kind>>::Output>;
1852
1853        #[track_caller]
1854        fn mul(self, rhs: Matrix<Rhs>) -> Self::Output {
1855            self * &rhs
1856        }
1857    }
1858
1859    impl<Lhs: GenericMatrix, Rhs: GenericMatrix> Mul<Matrix<Rhs>> for Matrix<Lhs>
1860    where
1861        Lhs::Elem: Conjugate,
1862        Rhs::Elem: Conjugate<Canonical = <Lhs::Elem as Conjugate>::Canonical>,
1863        <Lhs::Elem as Conjugate>::Canonical: ComplexField,
1864        Lhs::Kind: MatMul<Rhs::Kind>,
1865    {
1866        type Output =
1867            KindOwn<<Lhs::Elem as Conjugate>::Canonical, <Lhs::Kind as MatMul<Rhs::Kind>>::Output>;
1868
1869        #[track_caller]
1870        fn mul(self, rhs: Matrix<Rhs>) -> Self::Output {
1871            &self * &rhs
1872        }
1873    }
1874
1875    impl<Lhs: GenericMatrix, Rhs: GenericMatrix> Add<&Matrix<Rhs>> for &Matrix<Lhs>
1876    where
1877        Lhs::Elem: Conjugate,
1878        Rhs::Elem: Conjugate<Canonical = <Lhs::Elem as Conjugate>::Canonical>,
1879        <Lhs::Elem as Conjugate>::Canonical: ComplexField,
1880        Lhs::Kind: MatAdd<Rhs::Kind>,
1881    {
1882        type Output =
1883            KindOwn<<Lhs::Elem as Conjugate>::Canonical, <Lhs::Kind as MatAdd<Rhs::Kind>>::Output>;
1884
1885        #[track_caller]
1886        fn add(self, rhs: &Matrix<Rhs>) -> Self::Output {
1887            <Lhs::Kind as MatAdd<Rhs::Kind>>::mat_add(
1888                GenericMatrix::as_ref(self),
1889                GenericMatrix::as_ref(rhs),
1890            )
1891        }
1892    }
1893    impl<Lhs: GenericMatrix, Rhs: GenericMatrix> Add<&Matrix<Rhs>> for Matrix<Lhs>
1894    where
1895        Lhs::Elem: Conjugate,
1896        Rhs::Elem: Conjugate<Canonical = <Lhs::Elem as Conjugate>::Canonical>,
1897        <Lhs::Elem as Conjugate>::Canonical: ComplexField,
1898        Lhs::Kind: MatAdd<Rhs::Kind>,
1899    {
1900        type Output =
1901            KindOwn<<Lhs::Elem as Conjugate>::Canonical, <Lhs::Kind as MatAdd<Rhs::Kind>>::Output>;
1902
1903        #[track_caller]
1904        fn add(self, rhs: &Matrix<Rhs>) -> Self::Output {
1905            &self + rhs
1906        }
1907    }
1908    impl<Lhs: GenericMatrix, Rhs: GenericMatrix> Add<Matrix<Rhs>> for &Matrix<Lhs>
1909    where
1910        Lhs::Elem: Conjugate,
1911        Rhs::Elem: Conjugate<Canonical = <Lhs::Elem as Conjugate>::Canonical>,
1912        <Lhs::Elem as Conjugate>::Canonical: ComplexField,
1913        Lhs::Kind: MatAdd<Rhs::Kind>,
1914    {
1915        type Output =
1916            KindOwn<<Lhs::Elem as Conjugate>::Canonical, <Lhs::Kind as MatAdd<Rhs::Kind>>::Output>;
1917
1918        #[track_caller]
1919        fn add(self, rhs: Matrix<Rhs>) -> Self::Output {
1920            self + &rhs
1921        }
1922    }
1923    impl<Lhs: GenericMatrix, Rhs: GenericMatrix> Add<Matrix<Rhs>> for Matrix<Lhs>
1924    where
1925        Lhs::Elem: Conjugate,
1926        Rhs::Elem: Conjugate<Canonical = <Lhs::Elem as Conjugate>::Canonical>,
1927        <Lhs::Elem as Conjugate>::Canonical: ComplexField,
1928        Lhs::Kind: MatAdd<Rhs::Kind>,
1929    {
1930        type Output =
1931            KindOwn<<Lhs::Elem as Conjugate>::Canonical, <Lhs::Kind as MatAdd<Rhs::Kind>>::Output>;
1932
1933        #[track_caller]
1934        fn add(self, rhs: Matrix<Rhs>) -> Self::Output {
1935            &self + &rhs
1936        }
1937    }
1938
1939    impl<Lhs: GenericMatrix, Rhs: GenericMatrix> Sub<&Matrix<Rhs>> for &Matrix<Lhs>
1940    where
1941        Lhs::Elem: Conjugate,
1942        Rhs::Elem: Conjugate<Canonical = <Lhs::Elem as Conjugate>::Canonical>,
1943        <Lhs::Elem as Conjugate>::Canonical: ComplexField,
1944        Lhs::Kind: MatSub<Rhs::Kind>,
1945    {
1946        type Output =
1947            KindOwn<<Lhs::Elem as Conjugate>::Canonical, <Lhs::Kind as MatSub<Rhs::Kind>>::Output>;
1948
1949        #[track_caller]
1950        fn sub(self, rhs: &Matrix<Rhs>) -> Self::Output {
1951            <Lhs::Kind as MatSub<Rhs::Kind>>::mat_sub(
1952                GenericMatrix::as_ref(self),
1953                GenericMatrix::as_ref(rhs),
1954            )
1955        }
1956    }
1957
1958    impl<Lhs: GenericMatrix, Rhs: GenericMatrix> Sub<&Matrix<Rhs>> for Matrix<Lhs>
1959    where
1960        Lhs::Elem: Conjugate,
1961        Rhs::Elem: Conjugate<Canonical = <Lhs::Elem as Conjugate>::Canonical>,
1962        <Lhs::Elem as Conjugate>::Canonical: ComplexField,
1963        Lhs::Kind: MatSub<Rhs::Kind>,
1964    {
1965        type Output =
1966            KindOwn<<Lhs::Elem as Conjugate>::Canonical, <Lhs::Kind as MatSub<Rhs::Kind>>::Output>;
1967
1968        #[track_caller]
1969        fn sub(self, rhs: &Matrix<Rhs>) -> Self::Output {
1970            &self - rhs
1971        }
1972    }
1973    impl<Lhs: GenericMatrix, Rhs: GenericMatrix> Sub<Matrix<Rhs>> for &Matrix<Lhs>
1974    where
1975        Lhs::Elem: Conjugate,
1976        Rhs::Elem: Conjugate<Canonical = <Lhs::Elem as Conjugate>::Canonical>,
1977        <Lhs::Elem as Conjugate>::Canonical: ComplexField,
1978        Lhs::Kind: MatSub<Rhs::Kind>,
1979    {
1980        type Output =
1981            KindOwn<<Lhs::Elem as Conjugate>::Canonical, <Lhs::Kind as MatSub<Rhs::Kind>>::Output>;
1982
1983        #[track_caller]
1984        fn sub(self, rhs: Matrix<Rhs>) -> Self::Output {
1985            self - &rhs
1986        }
1987    }
1988    impl<Lhs: GenericMatrix, Rhs: GenericMatrix> Sub<Matrix<Rhs>> for Matrix<Lhs>
1989    where
1990        Lhs::Elem: Conjugate,
1991        Rhs::Elem: Conjugate<Canonical = <Lhs::Elem as Conjugate>::Canonical>,
1992        <Lhs::Elem as Conjugate>::Canonical: ComplexField,
1993        Lhs::Kind: MatSub<Rhs::Kind>,
1994    {
1995        type Output =
1996            KindOwn<<Lhs::Elem as Conjugate>::Canonical, <Lhs::Kind as MatSub<Rhs::Kind>>::Output>;
1997
1998        #[track_caller]
1999        fn sub(self, rhs: Matrix<Rhs>) -> Self::Output {
2000            &self - &rhs
2001        }
2002    }
2003
2004    impl<Mat: GenericMatrix> Neg for &Matrix<Mat>
2005    where
2006        Mat::Elem: Conjugate,
2007        <Mat::Elem as Conjugate>::Canonical: ComplexField,
2008        Mat::Kind: MatNeg,
2009    {
2010        type Output = KindOwn<<Mat::Elem as Conjugate>::Canonical, <Mat::Kind as MatNeg>::Output>;
2011        fn neg(self) -> Self::Output {
2012            <Mat::Kind as MatNeg>::mat_neg(GenericMatrix::as_ref(self))
2013        }
2014    }
2015    impl<Mat: GenericMatrix> Neg for Matrix<Mat>
2016    where
2017        Mat::Elem: Conjugate,
2018        <Mat::Elem as Conjugate>::Canonical: ComplexField,
2019        Mat::Kind: MatNeg,
2020    {
2021        type Output = KindOwn<<Mat::Elem as Conjugate>::Canonical, <Mat::Kind as MatNeg>::Output>;
2022        fn neg(self) -> Self::Output {
2023            -&self
2024        }
2025    }
2026
2027    impl<Lhs: GenericMatrix, Rhs: GenericMatrix> PartialEq<Matrix<Rhs>> for Matrix<Lhs>
2028    where
2029        Lhs::Elem: Conjugate,
2030        Rhs::Elem: Conjugate<Canonical = <Lhs::Elem as Conjugate>::Canonical>,
2031        <Lhs::Elem as Conjugate>::Canonical: ComplexField,
2032        Lhs::Kind: MatEq<Rhs::Kind>,
2033    {
2034        fn eq(&self, rhs: &Matrix<Rhs>) -> bool {
2035            <Lhs::Kind as MatEq<Rhs::Kind>>::mat_eq(
2036                GenericMatrix::as_ref(self),
2037                GenericMatrix::as_ref(rhs),
2038            )
2039        }
2040    }
2041
2042    impl<Lhs: GenericMatrixMut, Rhs: GenericMatrix> MulAssign<&Matrix<Rhs>> for Matrix<Lhs>
2043    where
2044        Lhs::Elem: ComplexField,
2045        Rhs::Elem: Conjugate<Canonical = Lhs::Elem>,
2046        Lhs::Kind: MatMulAssign<Rhs::Kind>,
2047    {
2048        #[track_caller]
2049        fn mul_assign(&mut self, rhs: &Matrix<Rhs>) {
2050            <Lhs::Kind as MatMulAssign<Rhs::Kind>>::mat_mul_assign(
2051                GenericMatrixMut::as_mut(self),
2052                GenericMatrix::as_ref(rhs),
2053            );
2054        }
2055    }
2056    impl<Lhs: GenericMatrixMut, Rhs: GenericMatrix> MulAssign<Matrix<Rhs>> for Matrix<Lhs>
2057    where
2058        Lhs::Elem: ComplexField,
2059        Rhs::Elem: Conjugate<Canonical = Lhs::Elem>,
2060        Lhs::Kind: MatMulAssign<Rhs::Kind>,
2061    {
2062        #[track_caller]
2063        fn mul_assign(&mut self, rhs: Matrix<Rhs>) {
2064            *self *= &rhs;
2065        }
2066    }
2067
2068    impl<Lhs: GenericMatrixMut, Rhs: GenericMatrix> AddAssign<&Matrix<Rhs>> for Matrix<Lhs>
2069    where
2070        Lhs::Elem: ComplexField,
2071        Rhs::Elem: Conjugate<Canonical = Lhs::Elem>,
2072        Lhs::Kind: MatAddAssign<Rhs::Kind>,
2073    {
2074        #[track_caller]
2075        fn add_assign(&mut self, rhs: &Matrix<Rhs>) {
2076            <Lhs::Kind as MatAddAssign<Rhs::Kind>>::mat_add_assign(
2077                GenericMatrixMut::as_mut(self),
2078                GenericMatrix::as_ref(rhs),
2079            );
2080        }
2081    }
2082    impl<Lhs: GenericMatrixMut, Rhs: GenericMatrix> AddAssign<Matrix<Rhs>> for Matrix<Lhs>
2083    where
2084        Lhs::Elem: ComplexField,
2085        Rhs::Elem: Conjugate<Canonical = Lhs::Elem>,
2086        Lhs::Kind: MatAddAssign<Rhs::Kind>,
2087    {
2088        #[track_caller]
2089        fn add_assign(&mut self, rhs: Matrix<Rhs>) {
2090            *self += &rhs;
2091        }
2092    }
2093
2094    impl<Lhs: GenericMatrixMut, Rhs: GenericMatrix> SubAssign<&Matrix<Rhs>> for Matrix<Lhs>
2095    where
2096        Lhs::Elem: ComplexField,
2097        Rhs::Elem: Conjugate<Canonical = Lhs::Elem>,
2098        Lhs::Kind: MatSubAssign<Rhs::Kind>,
2099    {
2100        #[track_caller]
2101        fn sub_assign(&mut self, rhs: &Matrix<Rhs>) {
2102            <Lhs::Kind as MatSubAssign<Rhs::Kind>>::mat_sub_assign(
2103                GenericMatrixMut::as_mut(self),
2104                GenericMatrix::as_ref(rhs),
2105            );
2106        }
2107    }
2108    impl<Lhs: GenericMatrixMut, Rhs: GenericMatrix> SubAssign<Matrix<Rhs>> for Matrix<Lhs>
2109    where
2110        Lhs::Elem: ComplexField,
2111        Rhs::Elem: Conjugate<Canonical = Lhs::Elem>,
2112        Lhs::Kind: MatSubAssign<Rhs::Kind>,
2113    {
2114        #[track_caller]
2115        fn sub_assign(&mut self, rhs: Matrix<Rhs>) {
2116            *self -= &rhs;
2117        }
2118    }
2119};
2120
2121#[cfg(test)]
2122#[allow(non_snake_case)]
2123mod test {
2124    use crate::{
2125        assert, mat,
2126        permutation::{Permutation, PermutationRef},
2127        Col, Mat, Row,
2128    };
2129    use assert_approx_eq::assert_approx_eq;
2130
2131    fn matrices() -> (Mat<f64>, Mat<f64>) {
2132        let A = mat![[2.8, -3.3], [-1.7, 5.2], [4.6, -8.3],];
2133
2134        let B = mat![[-7.9, 8.3], [4.7, -3.2], [3.8, -5.2],];
2135        (A, B)
2136    }
2137
2138    #[test]
2139    #[should_panic]
2140    fn test_adding_matrices_of_different_sizes_should_panic() {
2141        let A = mat![[1.0, 2.0], [3.0, 4.0]];
2142        let B = mat![[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]];
2143        _ = A + B;
2144    }
2145
2146    #[test]
2147    #[should_panic]
2148    fn test_subtracting_two_matrices_of_different_sizes_should_panic() {
2149        let A = mat![[1.0, 2.0], [3.0, 4.0]];
2150        let B = mat![[1.0, 2.0, 3.0], [4.0, 5.0, 6.0]];
2151        _ = A - B;
2152    }
2153
2154    #[test]
2155    fn test_add() {
2156        let (A, B) = matrices();
2157
2158        let expected = mat![[-5.1, 5.0], [3.0, 2.0], [8.4, -13.5],];
2159
2160        assert_matrix_approx_eq(A.as_ref() + B.as_ref(), &expected);
2161        assert_matrix_approx_eq(&A + &B, &expected);
2162        assert_matrix_approx_eq(A.as_ref() + &B, &expected);
2163        assert_matrix_approx_eq(&A + B.as_ref(), &expected);
2164        assert_matrix_approx_eq(A.as_ref() + B.clone(), &expected);
2165        assert_matrix_approx_eq(&A + B.clone(), &expected);
2166        assert_matrix_approx_eq(A.clone() + B.as_ref(), &expected);
2167        assert_matrix_approx_eq(A.clone() + &B, &expected);
2168        assert_matrix_approx_eq(A + B, &expected);
2169    }
2170
2171    #[test]
2172    fn test_sub() {
2173        let (A, B) = matrices();
2174
2175        let expected = mat![[10.7, -11.6], [-6.4, 8.4], [0.8, -3.1],];
2176
2177        assert_matrix_approx_eq(A.as_ref() - B.as_ref(), &expected);
2178        assert_matrix_approx_eq(&A - &B, &expected);
2179        assert_matrix_approx_eq(A.as_ref() - &B, &expected);
2180        assert_matrix_approx_eq(&A - B.as_ref(), &expected);
2181        assert_matrix_approx_eq(A.as_ref() - B.clone(), &expected);
2182        assert_matrix_approx_eq(&A - B.clone(), &expected);
2183        assert_matrix_approx_eq(A.clone() - B.as_ref(), &expected);
2184        assert_matrix_approx_eq(A.clone() - &B, &expected);
2185        assert_matrix_approx_eq(A - B, &expected);
2186    }
2187
2188    #[test]
2189    fn test_neg() {
2190        let (A, _) = matrices();
2191
2192        let expected = mat![[-2.8, 3.3], [1.7, -5.2], [-4.6, 8.3],];
2193
2194        assert_eq!(-A, expected);
2195    }
2196
2197    #[test]
2198    fn test_scalar_mul() {
2199        use crate::scale;
2200
2201        let (A, _) = matrices();
2202        let scale = scale(3.0);
2203        let expected = Mat::from_fn(A.nrows(), A.ncols(), |i, j| A.read(i, j) * scale.value());
2204
2205        {
2206            assert_matrix_approx_eq(A.as_ref() * scale, &expected);
2207            assert_matrix_approx_eq(&A * scale, &expected);
2208            assert_matrix_approx_eq(A.as_ref() * scale, &expected);
2209            assert_matrix_approx_eq(&A * scale, &expected);
2210            assert_matrix_approx_eq(A.as_ref() * scale, &expected);
2211            assert_matrix_approx_eq(&A * scale, &expected);
2212            assert_matrix_approx_eq(A.clone() * scale, &expected);
2213            assert_matrix_approx_eq(A.clone() * scale, &expected);
2214            assert_matrix_approx_eq(A * scale, &expected);
2215        }
2216
2217        let (A, _) = matrices();
2218        {
2219            assert_matrix_approx_eq(scale * A.as_ref(), &expected);
2220            assert_matrix_approx_eq(scale * &A, &expected);
2221            assert_matrix_approx_eq(scale * A.as_ref(), &expected);
2222            assert_matrix_approx_eq(scale * &A, &expected);
2223            assert_matrix_approx_eq(scale * A.as_ref(), &expected);
2224            assert_matrix_approx_eq(scale * &A, &expected);
2225            assert_matrix_approx_eq(scale * A.clone(), &expected);
2226            assert_matrix_approx_eq(scale * A.clone(), &expected);
2227            assert_matrix_approx_eq(scale * A, &expected);
2228        }
2229    }
2230
2231    #[test]
2232    fn test_diag_mul() {
2233        let (A, _) = matrices();
2234        let diag_left = mat![[1.0, 0.0, 0.0], [0.0, 2.0, 0.0], [0.0, 0.0, 3.0]];
2235        let diag_right = mat![[4.0, 0.0], [0.0, 5.0]];
2236
2237        assert!(&diag_left * &A == diag_left.diagonal() * &A);
2238        assert!(&A * &diag_right == &A * diag_right.diagonal());
2239    }
2240
2241    #[test]
2242    fn test_perm_mul() {
2243        let A = Mat::from_fn(6, 5, |i, j| (j + 5 * i) as f64);
2244        let pl = Permutation::<usize, f64>::new_checked(
2245            Box::new([5, 1, 4, 0, 2, 3]),
2246            Box::new([3, 1, 4, 5, 2, 0]),
2247        );
2248        let pr = Permutation::<usize, f64>::new_checked(
2249            Box::new([1, 4, 0, 2, 3]),
2250            Box::new([2, 0, 3, 4, 1]),
2251        );
2252
2253        let perm_left = mat![
2254            [0.0, 0.0, 0.0, 0.0, 0.0, 1.0],
2255            [0.0, 1.0, 0.0, 0.0, 0.0, 0.0],
2256            [0.0, 0.0, 0.0, 0.0, 1.0, 0.0],
2257            [1.0, 0.0, 0.0, 0.0, 0.0, 0.0],
2258            [0.0, 0.0, 1.0, 0.0, 0.0, 0.0],
2259            [0.0, 0.0, 0.0, 1.0, 0.0, 0.0],
2260        ];
2261        let perm_right = mat![
2262            [0.0, 1.0, 0.0, 0.0, 0.0],
2263            [0.0, 0.0, 0.0, 0.0, 1.0],
2264            [1.0, 0.0, 0.0, 0.0, 0.0],
2265            [0.0, 0.0, 1.0, 0.0, 0.0],
2266            [0.0, 0.0, 0.0, 1.0, 0.0],
2267        ];
2268
2269        assert!(
2270            &pl * pl.as_ref().inverse()
2271                == PermutationRef::<'_, usize, f64>::new_checked(
2272                    &[0, 1, 2, 3, 4, 5],
2273                    &[0, 1, 2, 3, 4, 5],
2274                )
2275        );
2276        assert!(&perm_left * &A == &pl * &A);
2277        assert!(&A * &perm_right == &A * &pr);
2278    }
2279
2280    #[test]
2281    fn test_matmul_col_row() {
2282        let A = Col::from_fn(6, |i| i as f64);
2283        let B = Row::from_fn(6, |j| (5 * j + 1) as f64);
2284
2285        // outer product
2286        assert_eq!(&A * &B, A.as_ref().as_2d() * B.as_ref().as_2d());
2287        // inner product
2288        assert_eq!(
2289            &B * &A,
2290            (B.as_ref().as_2d() * A.as_ref().as_2d()).read(0, 0),
2291        );
2292    }
2293
2294    fn assert_matrix_approx_eq(given: Mat<f64>, expected: &Mat<f64>) {
2295        assert_eq!(given.nrows(), expected.nrows());
2296        assert_eq!(given.ncols(), expected.ncols());
2297        for i in 0..given.nrows() {
2298            for j in 0..given.ncols() {
2299                assert_approx_eq!(given.read(i, j), expected.read(i, j));
2300            }
2301        }
2302    }
2303}