1use 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#[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#[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
37macro_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 #[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 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 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
242macro_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);