1use num::{One, Zero};
2use std::iter;
3use std::ops::{
4 Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Sub, SubAssign,
5};
6
7use simba::scalar::{
8 ClosedAddAssign, ClosedDivAssign, ClosedMulAssign, ClosedNeg, ClosedSubAssign,
9};
10
11use crate::base::allocator::{Allocator, SameShapeAllocator, SameShapeC, SameShapeR};
12use crate::base::blas_uninit::gemm_uninit;
13use crate::base::constraint::{
14 AreMultipliable, DimEq, SameNumberOfColumns, SameNumberOfRows, ShapeConstraint,
15};
16use crate::base::dimension::{Dim, DimMul, DimName, DimProd, Dyn};
17use crate::base::storage::{Storage, StorageMut};
18use crate::base::uninit::Uninit;
19use crate::base::{DefaultAllocator, Matrix, MatrixSum, OMatrix, Scalar, VectorView};
20use crate::storage::IsContiguous;
21use crate::uninit::{Init, InitStatus};
22use crate::{RawStorage, RawStorageMut, SimdComplexField};
23use std::mem::MaybeUninit;
24
25impl<T, R: Dim, C: Dim, S: RawStorage<T, R, C>> Index<usize> for Matrix<T, R, C, S> {
31 type Output = T;
32
33 #[inline]
34 fn index(&self, i: usize) -> &Self::Output {
35 let ij = self.vector_to_matrix_index(i);
36 &self[ij]
37 }
38}
39
40impl<T, R: Dim, C: Dim, S: RawStorage<T, R, C>> Index<(usize, usize)> for Matrix<T, R, C, S> {
41 type Output = T;
42
43 #[inline]
44 fn index(&self, ij: (usize, usize)) -> &Self::Output {
45 let shape = self.shape();
46 assert!(
47 ij.0 < shape.0 && ij.1 < shape.1,
48 "Matrix index out of bounds."
49 );
50
51 unsafe { self.get_unchecked((ij.0, ij.1)) }
52 }
53}
54
55impl<T, R: Dim, C: Dim, S: RawStorageMut<T, R, C>> IndexMut<usize> for Matrix<T, R, C, S> {
57 #[inline]
58 fn index_mut(&mut self, i: usize) -> &mut T {
59 let ij = self.vector_to_matrix_index(i);
60 &mut self[ij]
61 }
62}
63
64impl<T, R: Dim, C: Dim, S: RawStorageMut<T, R, C>> IndexMut<(usize, usize)> for Matrix<T, R, C, S> {
65 #[inline]
66 fn index_mut(&mut self, ij: (usize, usize)) -> &mut T {
67 let shape = self.shape();
68 assert!(
69 ij.0 < shape.0 && ij.1 < shape.1,
70 "Matrix index out of bounds."
71 );
72
73 unsafe { self.get_unchecked_mut((ij.0, ij.1)) }
74 }
75}
76
77impl<T, R: Dim, C: Dim, S> Neg for Matrix<T, R, C, S>
83where
84 T: Scalar + ClosedNeg,
85 S: Storage<T, R, C>,
86 DefaultAllocator: Allocator<R, C>,
87{
88 type Output = OMatrix<T, R, C>;
89
90 #[inline]
91 fn neg(self) -> Self::Output {
92 let mut res = self.into_owned();
93 res.neg_mut();
94 res
95 }
96}
97
98impl<'a, T, R: Dim, C: Dim, S> Neg for &'a Matrix<T, R, C, S>
99where
100 T: Scalar + ClosedNeg,
101 S: Storage<T, R, C>,
102 DefaultAllocator: Allocator<R, C>,
103{
104 type Output = OMatrix<T, R, C>;
105
106 #[inline]
107 fn neg(self) -> Self::Output {
108 -self.clone_owned()
109 }
110}
111
112impl<T, R: Dim, C: Dim, S> Matrix<T, R, C, S>
113where
114 T: Scalar + ClosedNeg,
115 S: StorageMut<T, R, C>,
116{
117 #[inline]
119 pub fn neg_mut(&mut self) {
120 for e in self.iter_mut() {
121 *e = -e.clone()
122 }
123 }
124}
125
126macro_rules! componentwise_binop_impl(
133 ($Trait: ident, $method: ident, $bound: ident;
134 $TraitAssign: ident, $method_assign: ident, $method_assign_statically_unchecked: ident,
135 $method_assign_statically_unchecked_rhs: ident;
136 $method_to: ident, $method_to_statically_unchecked_uninit: ident) => {
137
138 impl<T, R1: Dim, C1: Dim, SA: Storage<T, R1, C1>> Matrix<T, R1, C1, SA>
139 where T: Scalar + $bound {
140
141 #[inline]
149 fn $method_to_statically_unchecked_uninit<Status, R2: Dim, C2: Dim, SB,
150 R3: Dim, C3: Dim, SC>(&self,
151 _status: Status,
152 rhs: &Matrix<T, R2, C2, SB>,
153 out: &mut Matrix<Status::Value, R3, C3, SC>)
154 where Status: InitStatus<T>,
155 SB: RawStorage<T, R2, C2>,
156 SC: RawStorageMut<Status::Value, R3, C3> {
157 assert_eq!(self.shape(), rhs.shape(), "Matrix addition/subtraction dimensions mismatch.");
158 assert_eq!(self.shape(), out.shape(), "Matrix addition/subtraction output dimensions mismatch.");
159
160 unsafe {
163 if self.data.is_contiguous() && rhs.data.is_contiguous() && out.data.is_contiguous() {
164 let arr1 = self.data.as_slice_unchecked();
165 let arr2 = rhs.data.as_slice_unchecked();
166 let out = out.data.as_mut_slice_unchecked();
167 for i in 0 .. arr1.len() {
168 Status::init(out.get_unchecked_mut(i), arr1.get_unchecked(i).clone().$method(arr2.get_unchecked(i).clone()));
169 }
170 } else {
171 for j in 0 .. self.ncols() {
172 for i in 0 .. self.nrows() {
173 let val = self.get_unchecked((i, j)).clone().$method(rhs.get_unchecked((i, j)).clone());
174 Status::init(out.get_unchecked_mut((i, j)), val);
175 }
176 }
177 }
178 }
179 }
180
181
182 #[inline]
183 fn $method_assign_statically_unchecked<R2, C2, SB>(&mut self, rhs: &Matrix<T, R2, C2, SB>)
184 where R2: Dim,
185 C2: Dim,
186 SA: StorageMut<T, R1, C1>,
187 SB: Storage<T, R2, C2> {
188 assert_eq!(self.shape(), rhs.shape(), "Matrix addition/subtraction dimensions mismatch.");
189
190 unsafe {
193 if self.data.is_contiguous() && rhs.data.is_contiguous() {
194 let arr1 = self.data.as_mut_slice_unchecked();
195 let arr2 = rhs.data.as_slice_unchecked();
196
197 for i in 0 .. arr2.len() {
198 arr1.get_unchecked_mut(i).$method_assign(arr2.get_unchecked(i).clone());
199 }
200 } else {
201 for j in 0 .. rhs.ncols() {
202 for i in 0 .. rhs.nrows() {
203 self.get_unchecked_mut((i, j)).$method_assign(rhs.get_unchecked((i, j)).clone())
204 }
205 }
206 }
207 }
208 }
209
210
211 #[inline]
212 fn $method_assign_statically_unchecked_rhs<R2, C2, SB>(&self, rhs: &mut Matrix<T, R2, C2, SB>)
213 where R2: Dim,
214 C2: Dim,
215 SB: StorageMut<T, R2, C2> {
216 assert_eq!(self.shape(), rhs.shape(), "Matrix addition/subtraction dimensions mismatch.");
217
218 unsafe {
221 if self.data.is_contiguous() && rhs.data.is_contiguous() {
222 let arr1 = self.data.as_slice_unchecked();
223 let arr2 = rhs.data.as_mut_slice_unchecked();
224
225 for i in 0 .. arr1.len() {
226 let res = arr1.get_unchecked(i).clone().$method(arr2.get_unchecked(i).clone());
227 *arr2.get_unchecked_mut(i) = res;
228 }
229 } else {
230 for j in 0 .. self.ncols() {
231 for i in 0 .. self.nrows() {
232 let r = rhs.get_unchecked_mut((i, j));
233 *r = self.get_unchecked((i, j)).clone().$method(r.clone())
234 }
235 }
236 }
237 }
238 }
239
240
241 #[inline]
250 pub fn $method_to<R2: Dim, C2: Dim, SB,
251 R3: Dim, C3: Dim, SC>(&self,
252 rhs: &Matrix<T, R2, C2, SB>,
253 out: &mut Matrix<T, R3, C3, SC>)
254 where SB: Storage<T, R2, C2>,
255 SC: StorageMut<T, R3, C3>,
256 ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> +
257 SameNumberOfRows<R1, R3> + SameNumberOfColumns<C1, C3> {
258 self.$method_to_statically_unchecked_uninit(Init, rhs, out)
259 }
260 }
261
262 impl<'b, T, R1, C1, R2, C2, SA, SB> $Trait<&'b Matrix<T, R2, C2, SB>> for Matrix<T, R1, C1, SA>
263 where R1: Dim, C1: Dim, R2: Dim, C2: Dim,
264 T: Scalar + $bound,
265 SA: Storage<T, R1, C1>,
266 SB: Storage<T, R2, C2>,
267 DefaultAllocator: SameShapeAllocator<R1, C1, R2, C2>,
268 ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
269 type Output = MatrixSum<T, R1, C1, R2, C2>;
270
271 #[inline]
272 fn $method(self, rhs: &'b Matrix<T, R2, C2, SB>) -> Self::Output {
273 assert_eq!(self.shape(), rhs.shape(), "Matrix addition/subtraction dimensions mismatch.");
274 let mut res = self.into_owned_sum::<R2, C2>();
275 res.$method_assign_statically_unchecked(rhs);
276 res
277 }
278 }
279
280 impl<'a, T, R1, C1, R2, C2, SA, SB> $Trait<Matrix<T, R2, C2, SB>> for &'a Matrix<T, R1, C1, SA>
281 where R1: Dim, C1: Dim, R2: Dim, C2: Dim,
282 T: Scalar + $bound,
283 SA: Storage<T, R1, C1>,
284 SB: Storage<T, R2, C2>,
285 DefaultAllocator: SameShapeAllocator<R2, C2, R1, C1>,
286 ShapeConstraint: SameNumberOfRows<R2, R1> + SameNumberOfColumns<C2, C1> {
287 type Output = MatrixSum<T, R2, C2, R1, C1>;
288
289 #[inline]
290 fn $method(self, rhs: Matrix<T, R2, C2, SB>) -> Self::Output {
291 let mut rhs = rhs.into_owned_sum::<R1, C1>();
292 assert_eq!(self.shape(), rhs.shape(), "Matrix addition/subtraction dimensions mismatch.");
293 self.$method_assign_statically_unchecked_rhs(&mut rhs);
294 rhs
295 }
296 }
297
298 impl<T, R1, C1, R2, C2, SA, SB> $Trait<Matrix<T, R2, C2, SB>> for Matrix<T, R1, C1, SA>
299 where R1: Dim, C1: Dim, R2: Dim, C2: Dim,
300 T: Scalar + $bound,
301 SA: Storage<T, R1, C1>,
302 SB: Storage<T, R2, C2>,
303 DefaultAllocator: SameShapeAllocator<R1, C1, R2, C2>,
304 ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
305 type Output = MatrixSum<T, R1, C1, R2, C2>;
306
307 #[inline]
308 fn $method(self, rhs: Matrix<T, R2, C2, SB>) -> Self::Output {
309 self.$method(&rhs)
310 }
311 }
312
313 impl<'a, 'b, T, R1, C1, R2, C2, SA, SB> $Trait<&'b Matrix<T, R2, C2, SB>> for &'a Matrix<T, R1, C1, SA>
314 where R1: Dim, C1: Dim, R2: Dim, C2: Dim,
315 T: Scalar + $bound,
316 SA: Storage<T, R1, C1>,
317 SB: Storage<T, R2, C2>,
318 DefaultAllocator: SameShapeAllocator<R1, C1, R2, C2>,
319 ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
320 type Output = MatrixSum<T, R1, C1, R2, C2>;
321
322 #[inline]
323 fn $method(self, rhs: &'b Matrix<T, R2, C2, SB>) -> Self::Output {
324 let (nrows, ncols) = self.shape();
325 let nrows: SameShapeR<R1, R2> = Dim::from_usize(nrows);
326 let ncols: SameShapeC<C1, C2> = Dim::from_usize(ncols);
327 let mut res = Matrix::uninit(nrows, ncols);
328 self.$method_to_statically_unchecked_uninit(Uninit, rhs, &mut res);
329 unsafe { res.assume_init() }
331 }
332 }
333
334 impl<'b, T, R1, C1, R2, C2, SA, SB> $TraitAssign<&'b Matrix<T, R2, C2, SB>> for Matrix<T, R1, C1, SA>
335 where R1: Dim, C1: Dim, R2: Dim, C2: Dim,
336 T: Scalar + $bound,
337 SA: StorageMut<T, R1, C1>,
338 SB: Storage<T, R2, C2>,
339 ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
340
341 #[inline]
342 fn $method_assign(&mut self, rhs: &'b Matrix<T, R2, C2, SB>) {
343 self.$method_assign_statically_unchecked(rhs)
344 }
345 }
346
347 impl<T, R1, C1, R2, C2, SA, SB> $TraitAssign<Matrix<T, R2, C2, SB>> for Matrix<T, R1, C1, SA>
348 where R1: Dim, C1: Dim, R2: Dim, C2: Dim,
349 T: Scalar + $bound,
350 SA: StorageMut<T, R1, C1>,
351 SB: Storage<T, R2, C2>,
352 ShapeConstraint: SameNumberOfRows<R1, R2> + SameNumberOfColumns<C1, C2> {
353
354 #[inline]
355 fn $method_assign(&mut self, rhs: Matrix<T, R2, C2, SB>) {
356 self.$method_assign(&rhs)
357 }
358 }
359 }
360);
361
362componentwise_binop_impl!(Add, add, ClosedAddAssign;
363 AddAssign, add_assign, add_assign_statically_unchecked, add_assign_statically_unchecked_mut;
364 add_to, add_to_statically_unchecked_uninit);
365componentwise_binop_impl!(Sub, sub, ClosedSubAssign;
366 SubAssign, sub_assign, sub_assign_statically_unchecked, sub_assign_statically_unchecked_mut;
367 sub_to, sub_to_statically_unchecked_uninit);
368
369impl<T, R: DimName, C: DimName> iter::Sum for OMatrix<T, R, C>
370where
371 T: Scalar + ClosedAddAssign + Zero,
372 DefaultAllocator: Allocator<R, C>,
373{
374 fn sum<I: Iterator<Item = OMatrix<T, R, C>>>(iter: I) -> OMatrix<T, R, C> {
375 iter.fold(Matrix::zero(), |acc, x| acc + x)
376 }
377}
378
379impl<T, C: Dim> iter::Sum for OMatrix<T, Dyn, C>
380where
381 T: Scalar + ClosedAddAssign + Zero,
382 DefaultAllocator: Allocator<Dyn, C>,
383{
384 fn sum<I: Iterator<Item = OMatrix<T, Dyn, C>>>(mut iter: I) -> OMatrix<T, Dyn, C> {
401 if let Some(first) = iter.next() {
402 iter.fold(first, |acc, x| acc + x)
403 } else {
404 panic!("Cannot compute `sum` of empty iterator.")
405 }
406 }
407}
408
409impl<'a, T, R: DimName, C: DimName> iter::Sum<&'a OMatrix<T, R, C>> for OMatrix<T, R, C>
410where
411 T: Scalar + ClosedAddAssign + Zero,
412 DefaultAllocator: Allocator<R, C>,
413{
414 fn sum<I: Iterator<Item = &'a OMatrix<T, R, C>>>(iter: I) -> OMatrix<T, R, C> {
415 iter.fold(Matrix::zero(), |acc, x| acc + x)
416 }
417}
418
419impl<'a, T, C: Dim> iter::Sum<&'a OMatrix<T, Dyn, C>> for OMatrix<T, Dyn, C>
420where
421 T: Scalar + ClosedAddAssign + Zero,
422 DefaultAllocator: Allocator<Dyn, C>,
423{
424 fn sum<I: Iterator<Item = &'a OMatrix<T, Dyn, C>>>(mut iter: I) -> OMatrix<T, Dyn, C> {
441 if let Some(first) = iter.next() {
442 iter.fold(first.clone(), |acc, x| acc + x)
443 } else {
444 panic!("Cannot compute `sum` of empty iterator.")
445 }
446 }
447}
448
449macro_rules! componentwise_scalarop_impl(
458 ($Trait: ident, $method: ident, $bound: ident;
459 $TraitAssign: ident, $method_assign: ident) => {
460 impl<T, R: Dim, C: Dim, S> $Trait<T> for Matrix<T, R, C, S>
461 where T: Scalar + $bound,
462 S: Storage<T, R, C>,
463 DefaultAllocator: Allocator<R, C> {
464 type Output = OMatrix<T, R, C>;
465
466 #[inline]
467 fn $method(self, rhs: T) -> Self::Output {
468 let mut res = self.into_owned();
469
470 for left in res.as_mut_slice().iter_mut() {
477 *left = left.clone().$method(rhs.clone())
478 }
479
480 res
481 }
482 }
483
484 impl<'a, T, R: Dim, C: Dim, S> $Trait<T> for &'a Matrix<T, R, C, S>
485 where T: Scalar + $bound,
486 S: Storage<T, R, C>,
487 DefaultAllocator: Allocator<R, C> {
488 type Output = OMatrix<T, R, C>;
489
490 #[inline]
491 fn $method(self, rhs: T) -> Self::Output {
492 self.clone_owned().$method(rhs)
493 }
494 }
495
496 impl<T, R: Dim, C: Dim, S> $TraitAssign<T> for Matrix<T, R, C, S>
497 where T: Scalar + $bound,
498 S: StorageMut<T, R, C> {
499 #[inline]
500 fn $method_assign(&mut self, rhs: T) {
501 for j in 0 .. self.ncols() {
502 for i in 0 .. self.nrows() {
503 unsafe { self.get_unchecked_mut((i, j)).$method_assign(rhs.clone()) };
504 }
505 }
506 }
507 }
508 }
509);
510
511componentwise_scalarop_impl!(Mul, mul, ClosedMulAssign; MulAssign, mul_assign);
512componentwise_scalarop_impl!(Div, div, ClosedDivAssign; DivAssign, div_assign);
513
514macro_rules! left_scalar_mul_impl(
515 ($($T: ty),* $(,)*) => {$(
516 impl<R: Dim, C: Dim, S: Storage<$T, R, C>> Mul<Matrix<$T, R, C, S>> for $T
517 where DefaultAllocator: Allocator<R, C> {
518 type Output = OMatrix<$T, R, C>;
519
520 #[inline]
521 fn mul(self, rhs: Matrix<$T, R, C, S>) -> Self::Output {
522 let mut res = rhs.into_owned();
523
524 for rhs in res.as_mut_slice().iter_mut() {
531 *rhs *= self
532 }
533
534 res
535 }
536 }
537
538 impl<'b, R: Dim, C: Dim, S: Storage<$T, R, C>> Mul<&'b Matrix<$T, R, C, S>> for $T
539 where DefaultAllocator: Allocator<R, C> {
540 type Output = OMatrix<$T, R, C>;
541
542 #[inline]
543 fn mul(self, rhs: &'b Matrix<$T, R, C, S>) -> Self::Output {
544 self * rhs.clone_owned()
545 }
546 }
547 )*}
548);
549
550left_scalar_mul_impl!(u8, u16, u32, u64, usize, i8, i16, i32, i64, isize, f32, f64);
551
552impl<'a, 'b, T, R1: Dim, C1: Dim, R2: Dim, C2: Dim, SA, SB> Mul<&'b Matrix<T, R2, C2, SB>>
554 for &'a Matrix<T, R1, C1, SA>
555where
556 T: Scalar + Zero + One + ClosedAddAssign + ClosedMulAssign,
557 SA: Storage<T, R1, C1>,
558 SB: Storage<T, R2, C2>,
559 DefaultAllocator: Allocator<R1, C2>,
560 ShapeConstraint: AreMultipliable<R1, C1, R2, C2>,
561{
562 type Output = OMatrix<T, R1, C2>;
563
564 #[inline]
565 fn mul(self, rhs: &'b Matrix<T, R2, C2, SB>) -> Self::Output {
566 let mut res = Matrix::uninit(self.shape_generic().0, rhs.shape_generic().1);
567 unsafe {
568 gemm_uninit(Uninit, &mut res, T::one(), self, rhs, T::zero());
570 res.assume_init()
571 }
572 }
573}
574
575impl<'a, T, R1: Dim, C1: Dim, R2: Dim, C2: Dim, SA, SB> Mul<Matrix<T, R2, C2, SB>>
576 for &'a Matrix<T, R1, C1, SA>
577where
578 T: Scalar + Zero + One + ClosedAddAssign + ClosedMulAssign,
579 SB: Storage<T, R2, C2>,
580 SA: Storage<T, R1, C1>,
581 DefaultAllocator: Allocator<R1, C2>,
582 ShapeConstraint: AreMultipliable<R1, C1, R2, C2>,
583{
584 type Output = OMatrix<T, R1, C2>;
585
586 #[inline]
587 fn mul(self, rhs: Matrix<T, R2, C2, SB>) -> Self::Output {
588 self * &rhs
589 }
590}
591
592impl<'b, T, R1: Dim, C1: Dim, R2: Dim, C2: Dim, SA, SB> Mul<&'b Matrix<T, R2, C2, SB>>
593 for Matrix<T, R1, C1, SA>
594where
595 T: Scalar + Zero + One + ClosedAddAssign + ClosedMulAssign,
596 SB: Storage<T, R2, C2>,
597 SA: Storage<T, R1, C1>,
598 DefaultAllocator: Allocator<R1, C2>,
599 ShapeConstraint: AreMultipliable<R1, C1, R2, C2>,
600{
601 type Output = OMatrix<T, R1, C2>;
602
603 #[inline]
604 fn mul(self, rhs: &'b Matrix<T, R2, C2, SB>) -> Self::Output {
605 &self * rhs
606 }
607}
608
609impl<T, R1: Dim, C1: Dim, R2: Dim, C2: Dim, SA, SB> Mul<Matrix<T, R2, C2, SB>>
610 for Matrix<T, R1, C1, SA>
611where
612 T: Scalar + Zero + One + ClosedAddAssign + ClosedMulAssign,
613 SB: Storage<T, R2, C2>,
614 SA: Storage<T, R1, C1>,
615 DefaultAllocator: Allocator<R1, C2>,
616 ShapeConstraint: AreMultipliable<R1, C1, R2, C2>,
617{
618 type Output = OMatrix<T, R1, C2>;
619
620 #[inline]
621 fn mul(self, rhs: Matrix<T, R2, C2, SB>) -> Self::Output {
622 &self * &rhs
623 }
624}
625
626impl<T, R1, C1, R2, SA, SB> MulAssign<Matrix<T, R2, C1, SB>> for Matrix<T, R1, C1, SA>
630where
631 R1: Dim,
632 C1: Dim,
633 R2: Dim,
634 T: Scalar + Zero + One + ClosedAddAssign + ClosedMulAssign,
635 SB: Storage<T, R2, C1>,
636 SA: StorageMut<T, R1, C1> + IsContiguous + Clone, ShapeConstraint: AreMultipliable<R1, C1, R2, C1>,
638 DefaultAllocator: Allocator<R1, C1, Buffer<T> = SA>,
639{
640 #[inline]
641 fn mul_assign(&mut self, rhs: Matrix<T, R2, C1, SB>) {
642 *self = &*self * rhs
643 }
644}
645
646impl<'b, T, R1, C1, R2, SA, SB> MulAssign<&'b Matrix<T, R2, C1, SB>> for Matrix<T, R1, C1, SA>
647where
648 R1: Dim,
649 C1: Dim,
650 R2: Dim,
651 T: Scalar + Zero + One + ClosedAddAssign + ClosedMulAssign,
652 SB: Storage<T, R2, C1>,
653 SA: StorageMut<T, R1, C1> + IsContiguous + Clone, ShapeConstraint: AreMultipliable<R1, C1, R2, C1>,
655 DefaultAllocator: Allocator<R1, C1, Buffer<T> = SA>,
657{
658 #[inline]
659 fn mul_assign(&mut self, rhs: &'b Matrix<T, R2, C1, SB>) {
660 *self = &*self * rhs
661 }
662}
663
664impl<T, R1: Dim, C1: Dim, SA> Matrix<T, R1, C1, SA>
666where
667 T: Scalar + Zero + One + ClosedAddAssign + ClosedMulAssign,
668 SA: Storage<T, R1, C1>,
669{
670 #[inline]
672 #[must_use]
673 pub fn tr_mul<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<T, R2, C2, SB>) -> OMatrix<T, C1, C2>
674 where
675 SB: Storage<T, R2, C2>,
676 DefaultAllocator: Allocator<C1, C2>,
677 ShapeConstraint: SameNumberOfRows<R1, R2>,
678 {
679 let mut res = Matrix::uninit(self.shape_generic().1, rhs.shape_generic().1);
680 self.xx_mul_to_uninit(Uninit, rhs, &mut res, |a, b| a.dot(b));
681 unsafe { res.assume_init() }
683 }
684
685 #[inline]
687 #[must_use]
688 pub fn ad_mul<R2: Dim, C2: Dim, SB>(&self, rhs: &Matrix<T, R2, C2, SB>) -> OMatrix<T, C1, C2>
689 where
690 T: SimdComplexField,
691 SB: Storage<T, R2, C2>,
692 DefaultAllocator: Allocator<C1, C2>,
693 ShapeConstraint: SameNumberOfRows<R1, R2>,
694 {
695 let mut res = Matrix::uninit(self.shape_generic().1, rhs.shape_generic().1);
696 self.xx_mul_to_uninit(Uninit, rhs, &mut res, |a, b| a.dotc(b));
697 unsafe { res.assume_init() }
699 }
700
701 #[inline(always)]
702 fn xx_mul_to_uninit<Status, R2: Dim, C2: Dim, SB, R3: Dim, C3: Dim, SC>(
703 &self,
704 _status: Status,
705 rhs: &Matrix<T, R2, C2, SB>,
706 out: &mut Matrix<Status::Value, R3, C3, SC>,
707 dot: impl Fn(
708 &VectorView<'_, T, R1, SA::RStride, SA::CStride>,
709 &VectorView<'_, T, R2, SB::RStride, SB::CStride>,
710 ) -> T,
711 ) where
712 Status: InitStatus<T>,
713 SB: RawStorage<T, R2, C2>,
714 SC: RawStorageMut<Status::Value, R3, C3>,
715 ShapeConstraint: SameNumberOfRows<R1, R2> + DimEq<C1, R3> + DimEq<C2, C3>,
716 {
717 let (nrows1, ncols1) = self.shape();
718 let (nrows2, ncols2) = rhs.shape();
719 let (nrows3, ncols3) = out.shape();
720
721 assert!(
722 nrows1 == nrows2,
723 "Matrix multiplication dimensions mismatch {:?} and {:?}: left rows != right rows.",
724 self.shape(),
725 rhs.shape()
726 );
727 assert!(
728 ncols1 == nrows3,
729 "Matrix multiplication output dimensions mismatch {:?} and {:?}: left cols != right rows.",
730 self.shape(),
731 out.shape()
732 );
733 assert!(
734 ncols2 == ncols3,
735 "Matrix multiplication output dimensions mismatch {:?} and {:?}: left cols != right cols",
736 rhs.shape(),
737 out.shape()
738 );
739
740 for i in 0..ncols1 {
741 for j in 0..ncols2 {
742 let dot = dot(&self.column(i), &rhs.column(j));
743 let elt = unsafe { out.get_unchecked_mut((i, j)) };
744 Status::init(elt, dot);
745 }
746 }
747 }
748
749 #[inline]
752 pub fn tr_mul_to<R2: Dim, C2: Dim, SB, R3: Dim, C3: Dim, SC>(
753 &self,
754 rhs: &Matrix<T, R2, C2, SB>,
755 out: &mut Matrix<T, R3, C3, SC>,
756 ) where
757 SB: Storage<T, R2, C2>,
758 SC: StorageMut<T, R3, C3>,
759 ShapeConstraint: SameNumberOfRows<R1, R2> + DimEq<C1, R3> + DimEq<C2, C3>,
760 {
761 self.xx_mul_to_uninit(Init, rhs, out, |a, b| a.dot(b))
762 }
763
764 #[inline]
767 pub fn ad_mul_to<R2: Dim, C2: Dim, SB, R3: Dim, C3: Dim, SC>(
768 &self,
769 rhs: &Matrix<T, R2, C2, SB>,
770 out: &mut Matrix<T, R3, C3, SC>,
771 ) where
772 T: SimdComplexField,
773 SB: Storage<T, R2, C2>,
774 SC: StorageMut<T, R3, C3>,
775 ShapeConstraint: SameNumberOfRows<R1, R2> + DimEq<C1, R3> + DimEq<C2, C3>,
776 {
777 self.xx_mul_to_uninit(Init, rhs, out, |a, b| a.dotc(b))
778 }
779
780 #[inline]
782 pub fn mul_to<R2: Dim, C2: Dim, SB, R3: Dim, C3: Dim, SC>(
783 &self,
784 rhs: &Matrix<T, R2, C2, SB>,
785 out: &mut Matrix<T, R3, C3, SC>,
786 ) where
787 SB: Storage<T, R2, C2>,
788 SC: StorageMut<T, R3, C3>,
789 ShapeConstraint: SameNumberOfRows<R3, R1>
790 + SameNumberOfColumns<C3, C2>
791 + AreMultipliable<R1, C1, R2, C2>,
792 {
793 out.gemm(T::one(), self, rhs, T::zero());
794 }
795
796 #[must_use]
799 pub fn kronecker<R2: Dim, C2: Dim, SB>(
800 &self,
801 rhs: &Matrix<T, R2, C2, SB>,
802 ) -> OMatrix<T, DimProd<R1, R2>, DimProd<C1, C2>>
803 where
804 T: ClosedMulAssign,
805 R1: DimMul<R2>,
806 C1: DimMul<C2>,
807 SB: Storage<T, R2, C2>,
808 DefaultAllocator: Allocator<DimProd<R1, R2>, DimProd<C1, C2>>,
809 {
810 let (nrows1, ncols1) = self.shape_generic();
811 let (nrows2, ncols2) = rhs.shape_generic();
812
813 let mut res = Matrix::uninit(nrows1.mul(nrows2), ncols1.mul(ncols2));
814 let mut data_res = res.data.ptr_mut();
815
816 unsafe {
817 for j1 in 0..ncols1.value() {
818 for j2 in 0..ncols2.value() {
819 for i1 in 0..nrows1.value() {
820 let coeff = self.get_unchecked((i1, j1)).clone();
821
822 for i2 in 0..nrows2.value() {
823 *data_res = MaybeUninit::new(
824 coeff.clone() * rhs.get_unchecked((i2, j2)).clone(),
825 );
826 data_res = data_res.offset(1);
827 }
828 }
829 }
830 }
831
832 res.assume_init()
834 }
835 }
836}
837
838impl<T, D: DimName> iter::Product for OMatrix<T, D, D>
839where
840 T: Scalar + Zero + One + ClosedMulAssign + ClosedAddAssign,
841 DefaultAllocator: Allocator<D, D>,
842{
843 fn product<I: Iterator<Item = OMatrix<T, D, D>>>(iter: I) -> OMatrix<T, D, D> {
844 iter.fold(Matrix::one(), |acc, x| acc * x)
845 }
846}
847
848impl<'a, T, D: DimName> iter::Product<&'a OMatrix<T, D, D>> for OMatrix<T, D, D>
849where
850 T: Scalar + Zero + One + ClosedMulAssign + ClosedAddAssign,
851 DefaultAllocator: Allocator<D, D>,
852{
853 fn product<I: Iterator<Item = &'a OMatrix<T, D, D>>>(iter: I) -> OMatrix<T, D, D> {
854 iter.fold(Matrix::one(), |acc, x| acc * x)
855 }
856}