Skip to main content

a/math/matrix/
ops.rs

1//! The operators of matrices.
2
3use super::element::sealed::Element as Ring;
4use super::{Element, Matrix, Scalar};
5use crate::math::complex::Complex;
6use crate::math::numbers::Number;
7use core::ops::{Add, AddAssign, Div, DivAssign, Mul, MulAssign, Neg, Sub, SubAssign};
8
9/// Panics unless the two matrices have the same shape.
10#[inline]
11#[track_caller]
12fn same_shape<T>(a: &Matrix<T>, b: &Matrix<T>) {
13    if a.shape() != b.shape() {
14        different_shapes();
15    }
16}
17
18#[cold]
19#[inline(never)]
20#[track_caller]
21fn different_shapes() -> ! {
22    panic!("the matrices are not of the same shape")
23}
24
25/// `a ยท b`.
26#[track_caller]
27fn product<T: Element>(a: &Matrix<T>, b: &Matrix<T>) -> Matrix<T> {
28    assert!(
29        a.cols == b.rows,
30        "the columns of the left matrix are not as many as the rows of the right one"
31    );
32    let mut c = Matrix::zeros(a.rows, b.cols);
33    T::product(&mut c.data, &a.data, &b.data, a.rows, a.cols, b.cols);
34    c
35}
36
37/// An elementwise operator between two matrices, owned or borrowed, and its assignment.
38macro_rules! elementwise {
39    ($op:ident, $method:ident, $assign:ident, $assign_method:ident, $f:ident, $f_assign:ident) => {
40        impl<T: Element> $op<&Matrix<T>> for &Matrix<T> {
41            type Output = Matrix<T>;
42            #[track_caller]
43            fn $method(self, rhs: &Matrix<T>) -> Matrix<T> {
44                same_shape(self, rhs);
45                Matrix {
46                    rows: self.rows,
47                    cols: self.cols,
48                    data: self
49                        .data
50                        .iter()
51                        .zip(&rhs.data)
52                        .map(|(a, b)| T::$f(a, b))
53                        .collect(),
54                }
55            }
56        }
57        impl<T: Element> $op<&Matrix<T>> for Matrix<T> {
58            type Output = Matrix<T>;
59            #[track_caller]
60            fn $method(mut self, rhs: &Matrix<T>) -> Matrix<T> {
61                self.$assign_method(rhs);
62                self
63            }
64        }
65        impl<T: Element> $op<Matrix<T>> for Matrix<T> {
66            type Output = Matrix<T>;
67            #[track_caller]
68            fn $method(mut self, rhs: Matrix<T>) -> Matrix<T> {
69                self.$assign_method(&rhs);
70                self
71            }
72        }
73        impl<T: Element> $op<Matrix<T>> for &Matrix<T> {
74            type Output = Matrix<T>;
75            #[track_caller]
76            fn $method(self, mut rhs: Matrix<T>) -> Matrix<T> {
77                same_shape(self, &rhs);
78                for (b, a) in rhs.data.iter_mut().zip(&self.data) {
79                    *b = T::$f(a, b);
80                }
81                rhs
82            }
83        }
84        impl<T: Element> $assign<&Matrix<T>> for Matrix<T> {
85            #[track_caller]
86            fn $assign_method(&mut self, rhs: &Matrix<T>) {
87                same_shape(self, rhs);
88                for (a, b) in self.data.iter_mut().zip(&rhs.data) {
89                    T::$f_assign(a, b);
90                }
91            }
92        }
93        impl<T: Element> $assign<Matrix<T>> for Matrix<T> {
94            #[track_caller]
95            fn $assign_method(&mut self, rhs: Matrix<T>) {
96                self.$assign_method(&rhs);
97            }
98        }
99    };
100}
101
102elementwise!(Add, add, AddAssign, add_assign, add, add_assign);
103elementwise!(Sub, sub, SubAssign, sub_assign, sub, sub_assign);
104
105impl<T: Element> Neg for &Matrix<T> {
106    type Output = Matrix<T>;
107    fn neg(self) -> Matrix<T> {
108        self.map(T::neg)
109    }
110}
111
112impl<T: Element> Neg for Matrix<T> {
113    type Output = Matrix<T>;
114    fn neg(mut self) -> Matrix<T> {
115        for x in &mut self.data {
116            *x = T::neg(x);
117        }
118        self
119    }
120}
121
122impl<T: Element> Mul<&Matrix<T>> for &Matrix<T> {
123    type Output = Matrix<T>;
124    /// The matrix product.
125    ///
126    /// # Panics
127    ///
128    /// Panics if the columns of `self` are not as many as the rows of `rhs`.
129    #[track_caller]
130    fn mul(self, rhs: &Matrix<T>) -> Matrix<T> {
131        product(self, rhs)
132    }
133}
134
135impl<T: Element> Mul<Matrix<T>> for &Matrix<T> {
136    type Output = Matrix<T>;
137    #[track_caller]
138    fn mul(self, rhs: Matrix<T>) -> Matrix<T> {
139        product(self, &rhs)
140    }
141}
142
143impl<T: Element> Mul<&Matrix<T>> for Matrix<T> {
144    type Output = Matrix<T>;
145    #[track_caller]
146    fn mul(self, rhs: &Matrix<T>) -> Matrix<T> {
147        product(&self, rhs)
148    }
149}
150
151impl<T: Element> Mul<Matrix<T>> for Matrix<T> {
152    type Output = Matrix<T>;
153    #[track_caller]
154    fn mul(self, rhs: Matrix<T>) -> Matrix<T> {
155        product(&self, &rhs)
156    }
157}
158
159impl<T: Element> MulAssign<&Matrix<T>> for Matrix<T> {
160    #[track_caller]
161    fn mul_assign(&mut self, rhs: &Matrix<T>) {
162        *self = product(self, rhs);
163    }
164}
165
166impl<T: Element> MulAssign<Matrix<T>> for Matrix<T> {
167    #[track_caller]
168    fn mul_assign(&mut self, rhs: Matrix<T>) {
169        *self = product(self, &rhs);
170    }
171}
172
173impl<T: Element> Mul<&T> for &Matrix<T> {
174    type Output = Matrix<T>;
175    /// The product of every element by `rhs`.
176    fn mul(self, rhs: &T) -> Matrix<T> {
177        self.map(|x| T::mul(x, rhs))
178    }
179}
180
181impl<T: Element> Mul<T> for &Matrix<T> {
182    type Output = Matrix<T>;
183    fn mul(self, rhs: T) -> Matrix<T> {
184        self * &rhs
185    }
186}
187
188impl<T: Element> Mul<&T> for Matrix<T> {
189    type Output = Matrix<T>;
190    fn mul(mut self, rhs: &T) -> Matrix<T> {
191        self *= rhs;
192        self
193    }
194}
195
196impl<T: Element> Mul<T> for Matrix<T> {
197    type Output = Matrix<T>;
198    fn mul(mut self, rhs: T) -> Matrix<T> {
199        self *= &rhs;
200        self
201    }
202}
203
204impl<T: Element> MulAssign<&T> for Matrix<T> {
205    fn mul_assign(&mut self, rhs: &T) {
206        for x in &mut self.data {
207            T::mul_assign(x, rhs);
208        }
209    }
210}
211
212impl<T: Element> MulAssign<T> for Matrix<T> {
213    fn mul_assign(&mut self, rhs: T) {
214        *self *= &rhs;
215    }
216}
217
218impl<T: Scalar> Div<T> for &Matrix<T> {
219    type Output = Matrix<T>;
220    /// The quotient of every element by `rhs`.
221    fn div(self, rhs: T) -> Matrix<T> {
222        self.map(|&x| x / rhs)
223    }
224}
225
226impl<T: Scalar> Div<T> for Matrix<T> {
227    type Output = Matrix<T>;
228    fn div(mut self, rhs: T) -> Matrix<T> {
229        self /= rhs;
230        self
231    }
232}
233
234impl<T: Scalar> DivAssign<T> for Matrix<T> {
235    fn div_assign(&mut self, rhs: T) {
236        for x in &mut self.data {
237            *x /= rhs;
238        }
239    }
240}
241
242/// A scalar on the left of a matrix, which the orphan rule leaves to one implementation for each
243/// type of element.
244macro_rules! left {
245    ($t:ty) => {
246        impl Mul<&Matrix<$t>> for &$t {
247            type Output = Matrix<$t>;
248            fn mul(self, rhs: &Matrix<$t>) -> Matrix<$t> {
249                rhs.map(|x| <$t as Ring>::mul(self, x))
250            }
251        }
252        impl Mul<Matrix<$t>> for &$t {
253            type Output = Matrix<$t>;
254            fn mul(self, mut rhs: Matrix<$t>) -> Matrix<$t> {
255                for x in &mut rhs.data {
256                    *x = <$t as Ring>::mul(self, x);
257                }
258                rhs
259            }
260        }
261        impl Mul<&Matrix<$t>> for $t {
262            type Output = Matrix<$t>;
263            fn mul(self, rhs: &Matrix<$t>) -> Matrix<$t> {
264                &self * rhs
265            }
266        }
267        impl Mul<Matrix<$t>> for $t {
268            type Output = Matrix<$t>;
269            fn mul(self, rhs: Matrix<$t>) -> Matrix<$t> {
270                &self * rhs
271            }
272        }
273    };
274}
275
276left!(f32);
277left!(f64);
278left!(Complex<f32>);
279left!(Complex<f64>);
280left!(Number);