1use core::iter::Sum;
2use core::ops::{
3 Add, AddAssign, Div, DivAssign, Index, IndexMut, Mul, MulAssign, Neg, Not, Rem, RemAssign, Sub,
4 SubAssign,
5};
6
7use crate::index::MatrixIndex;
8use crate::num::Zero;
9use crate::Matrix;
10
11impl<T, I, const M: usize, const N: usize> Index<I> for Matrix<M, N, T>
16where
17 I: MatrixIndex<Self>,
18{
19 type Output = I::Output;
20
21 #[inline]
22 fn index(&self, index: I) -> &I::Output {
23 index.index(self)
24 }
25}
26
27impl<T, I, const M: usize, const N: usize> IndexMut<I> for Matrix<M, N, T>
28where
29 I: MatrixIndex<Self>,
30{
31 #[inline]
32 fn index_mut(&mut self, index: I) -> &mut I::Output {
33 index.index_mut(self)
34 }
35}
36
37macro_rules! impl_op_scalar {
42 ($trt:ident, $meth:ident) => {
43 impl<T, const M: usize, const N: usize> $trt<T> for Matrix<M, N, T>
45 where
46 T: Copy + $trt<Output = T>,
47 {
48 type Output = Matrix<M, N, T>;
49
50 fn $meth(mut self, other: T) -> Self::Output {
51 #[allow(clippy::suspicious_arithmetic_impl)]
52 for i in 0..(M * N) {
53 self[i] = self[i].$meth(other);
54 }
55 self
56 }
57 }
58
59 impl<T, const M: usize, const N: usize> $trt<&T> for Matrix<M, N, T>
61 where
62 T: Copy + $trt<Output = T>,
63 {
64 type Output = Matrix<M, N, T>;
65
66 fn $meth(mut self, other: &T) -> Self::Output {
67 #[allow(clippy::suspicious_arithmetic_impl)]
68 for i in 0..(M * N) {
69 self[i] = self[i].$meth(*other);
70 }
71 self
72 }
73 }
74
75 impl<T, const M: usize, const N: usize> $trt<T> for &Matrix<M, N, T>
77 where
78 T: Copy + Zero + $trt<Output = T>,
79 {
80 type Output = Matrix<M, N, T>;
81
82 fn $meth(self, other: T) -> Self::Output {
83 let mut matrix = Self::Output::zeros();
84 #[allow(clippy::suspicious_arithmetic_impl)]
85 for i in 0..(M * N) {
86 matrix[i] = self[i].$meth(other);
87 }
88 matrix
89 }
90 }
91
92 impl<T, const M: usize, const N: usize> $trt<&T> for &Matrix<M, N, T>
94 where
95 T: Copy + Zero + $trt<Output = T>,
96 {
97 type Output = Matrix<M, N, T>;
98
99 fn $meth(self, other: &T) -> Self::Output {
100 let mut matrix = Self::Output::zeros();
101 #[allow(clippy::suspicious_arithmetic_impl)]
102 for i in 0..(M * N) {
103 matrix[i] = self[i].$meth(*other);
104 }
105 matrix
106 }
107 }
108 };
109}
110
111impl_op_scalar! { Add, add }
112impl_op_scalar! { Sub, sub }
113impl_op_scalar! { Mul, mul }
114impl_op_scalar! { Div, div }
115impl_op_scalar! { Rem, rem }
116
117macro_rules! impl_op_assign_scalar {
122 ($trt:ident, $meth:ident) => {
123 impl<'a, T, const M: usize, const N: usize> $trt<T> for Matrix<M, N, T>
125 where
126 T: Copy + $trt<T>,
127 {
128 fn $meth(&mut self, other: T) {
129 #[allow(clippy::suspicious_arithmetic_impl, clippy::suspicious_op_assign_impl)]
130 for i in 0..(M * N) {
131 self[i].$meth(other);
132 }
133 }
134 }
135
136 impl<T, const M: usize, const N: usize> $trt<&T> for Matrix<M, N, T>
138 where
139 T: Copy + $trt<T>,
140 {
141 fn $meth(&mut self, other: &T) {
142 #[allow(clippy::suspicious_arithmetic_impl, clippy::suspicious_op_assign_impl)]
143 for i in 0..(M * N) {
144 self[i].$meth(*other);
145 }
146 }
147 }
148 };
149}
150
151impl_op_assign_scalar! { AddAssign, add_assign }
152impl_op_assign_scalar! { SubAssign, sub_assign }
153impl_op_assign_scalar! { MulAssign, mul_assign }
154impl_op_assign_scalar! { DivAssign, div_assign }
155impl_op_assign_scalar! { RemAssign, rem_assign }
156
157macro_rules! impl_op {
162 ($trt:ident, $meth:ident) => {
163 impl<T, const M: usize, const N: usize> $trt<Matrix<M, N, T>> for Matrix<M, N, T>
165 where
166 T: Copy + $trt<Output = T>,
167 {
168 type Output = Matrix<M, N, T>;
169
170 fn $meth(mut self, other: Matrix<M, N, T>) -> Self::Output {
171 #[allow(clippy::suspicious_arithmetic_impl, clippy::suspicious_op_assign_impl)]
172 for i in 0..(M * N) {
173 self[i] = self[i].$meth(other[i]);
174 }
175 self
176 }
177 }
178
179 impl<T, const M: usize, const N: usize> $trt<&Matrix<M, N, T>> for Matrix<M, N, T>
181 where
182 T: Copy + $trt<Output = T>,
183 {
184 type Output = Matrix<M, N, T>;
185
186 fn $meth(mut self, other: &Matrix<M, N, T>) -> Self::Output {
187 #[allow(clippy::suspicious_arithmetic_impl, clippy::suspicious_op_assign_impl)]
188 for i in 0..(M * N) {
189 self[i] = self[i].$meth(other[i]);
190 }
191 self
192 }
193 }
194
195 impl<T, const M: usize, const N: usize> $trt<Matrix<M, N, T>> for &Matrix<M, N, T>
197 where
198 T: Copy + Zero + $trt<Output = T>,
199 {
200 type Output = Matrix<M, N, T>;
201
202 fn $meth(self, other: Matrix<M, N, T>) -> Self::Output {
203 let mut matrix = *self;
204 #[allow(clippy::suspicious_arithmetic_impl, clippy::suspicious_op_assign_impl)]
205 for i in 0..(M * N) {
206 matrix[i] = self[i].$meth(other[i]);
207 }
208 matrix
209 }
210 }
211
212 impl<T, const M: usize, const N: usize> $trt<&Matrix<M, N, T>> for &Matrix<M, N, T>
214 where
215 T: Copy + Zero + $trt<Output = T>,
216 {
217 type Output = Matrix<M, N, T>;
218
219 fn $meth(self, other: &Matrix<M, N, T>) -> Self::Output {
220 let mut matrix = *self;
221 #[allow(clippy::suspicious_arithmetic_impl, clippy::suspicious_op_assign_impl)]
222 for i in 0..(M * N) {
223 matrix[i] = self[i].$meth(other[i]);
224 }
225 matrix
226 }
227 }
228 };
229}
230
231impl_op! { Add, add }
232impl_op! { Sub, sub }
233
234macro_rules! impl_op_mul {
239 ($lhs:ty, $rhs:ty) => {
240 impl<T, const N: usize, const M: usize, const P: usize> Mul<$rhs> for $lhs
241 where
242 T: Copy + Zero + Mul<Output = T> + Sum,
243 {
244 type Output = Matrix<M, P, T>;
245
246 fn mul(self, rhs: $rhs) -> Self::Output {
247 let mut matrix = Self::Output::zeros();
248 for i in 0..M {
249 for j in 0..P {
250 matrix[(i, j)] = self.row(i).dot(rhs.column(j));
251 }
252 }
253 matrix
254 }
255 }
256 };
257}
258
259impl_op_mul! { Matrix<M,N,T>, Matrix<N,P,T> }
260impl_op_mul! { Matrix<M,N,T>, &Matrix<N,P,T> }
261impl_op_mul! { &Matrix<M,N,T>, Matrix<N,P,T> }
262impl_op_mul! { &Matrix<M,N,T>, &Matrix<N,P,T> }
263
264macro_rules! impl_op_assign {
269 (impl $trt:ident<$rhs:ty>, $meth:ident) => {
270 impl<T, const M: usize, const N: usize> $trt<$rhs> for Matrix<M, N, T>
271 where
272 T: Copy + $trt,
273 {
274 fn $meth(&mut self, other: $rhs) {
275 #[allow(clippy::suspicious_arithmetic_impl, clippy::suspicious_op_assign_impl)]
276 for i in 0..(M * N) {
277 self[i].$meth(other[i]);
278 }
279 }
280 }
281 };
282}
283
284impl_op_assign! { impl AddAssign< Matrix<M,N,T>>, add_assign }
285impl_op_assign! { impl AddAssign<&Matrix<M,N,T>>, add_assign }
286impl_op_assign! { impl SubAssign< Matrix<M,N,T>>, sub_assign }
287impl_op_assign! { impl SubAssign<&Matrix<M,N,T>>, sub_assign }
288
289macro_rules! impl_op_unary {
294 ($trt:ident, $meth:ident) => {
295 impl<T, const M: usize, const N: usize> $trt for Matrix<M, N, T>
296 where
297 T: Copy + Zero + $trt<Output = T>,
298 {
299 type Output = Matrix<M, N, T>;
300
301 fn $meth(mut self) -> Self::Output {
302 #[allow(clippy::suspicious_arithmetic_impl, clippy::suspicious_op_assign_impl)]
303 for i in 0..(M * N) {
304 self[i] = self[i].$meth();
305 }
306 self
307 }
308 }
309
310 impl<T, const M: usize, const N: usize> $trt for &Matrix<M, N, T>
311 where
312 T: Copy + Zero + $trt<Output = T>,
313 {
314 type Output = Matrix<M, N, T>;
315
316 fn $meth(self) -> Self::Output {
317 let mut matrix = Self::Output::zeros();
318 #[allow(clippy::suspicious_arithmetic_impl, clippy::suspicious_op_assign_impl)]
319 for i in 0..(M * N) {
320 matrix[i] = self[i].$meth();
321 }
322 matrix
323 }
324 }
325 };
326}
327
328impl_op_unary! { Neg, neg }
329impl_op_unary! { Not, not }
330
331#[cfg(test)]
332mod tests {
333 use crate::*;
334 extern crate std;
335
336 #[ignore]
337 #[test]
338 fn time() {
339 use std::println;
340 use std::time::Instant;
341
342 let m = matrix![
343 2.0_f32, 3.0, 0.0, 9.0, 0.0, 1.0, 0.0, 1.0, 1.0, 2.0, 1.0;
344 1.0, 1.0, 0.0, 3.0, 0.0, 0.0, 0.0, 9.0, 2.0, 3.0, 1.0;
345 1.0, 4.0, 0.0, 2.0, 8.0, 5.0, 0.0, 3.0, 6.0, 1.0, 9.0;
346 0.0, 0.0, 0.0, 0.0, 0.0, 5.0, 0.0, 0.0, 0.0, 0.0, 0.0;
347 2.0, 2.0, 4.0, 1.0, 1.0, 2.0, 1.0, 6.0, 9.0, 0.0, 7.0;
348 0.0, 0.0, 0.0, 6.0, 0.0, 7.0, 0.0, 1.0, 0.0, 0.0, 0.0;
349 2.0, 5.0, 0.0, 7.0, 0.0, 4.0, 6.0, 8.0, 5.0, 1.0, 3.0;
350 0.0, 0.0, 0.0, 1.0, 0.0, 4.0, 0.0, 1.0, 0.0, 0.0, 0.0;
351 0.0, 0.0, 0.0, 8.0, 0.0, 2.0, 0.0, 0.0, 0.0, 0.0, 0.0;
352 2.0, 1.0, 0.0, 0.0, 0.0, 1.0, 0.0, 0.0, 2.0, 1.0, 1.0;
353 2.0, 6.0, 0.0, 1.0, 0.0,30.0, 0.0, 2.0, 3.0, 2.0, 1.0;
354 ];
355
356 let begin = Instant::now();
357 const N: usize = 1000000;
358 for _ in 0..N {
359 let _ = m * m;
360 }
361 let elapsed = (Instant::now() - begin).as_nanos();
362 println!(
363 "11x11 Matrix Multiplication: {} ns/call",
364 elapsed as f32 / N as f32
365 );
366
367 let begin = Instant::now();
368 for _ in 0..N {
369 let _ = m.inv();
370 }
371 let elapsed = (Instant::now() - begin).as_nanos();
372 println!(
373 "11x11 Matrix Inverse: {} ns/call",
374 elapsed as f32 / N as f32
375 );
376 }
377 #[test]
378 fn scalar() {
379 let m = matrix![
380 1.0, 2.0, 3.0;
381 4.0, 5.0, 6.0;
382 ];
383 let res = m + 3.0;
384 let exp = matrix![
385 4.0, 5.0, 6.0;
386 7.0, 8.0, 9.0;
387 ];
388 assert_eq!(res, exp);
389 let res = res - 3.0;
390 assert_eq!(res, m);
391 }
392 #[test]
393 fn mat_add() {
394 let m = matrix![
395 1.0, 2.0, 3.0;
396 4.0, 5.0, 6.0;
397 ];
398 let m2 = matrix![
399 1.0, 2.0, 3.0;
400 4.0, 5.0, 6.0;
401 ];
402 let exp = matrix![
403 2.0, 4.0, 6.0;
404 8.0, 10.0, 12.0;
405 ];
406 assert_eq!(m + m2, exp);
407 }
408 #[test]
409 fn mat_mul() {
410 let m = matrix![
411 1.0, 2.0, 3.0;
412 4.0, 5.0, 6.0;
413 ];
414 let m2 = matrix![
415 1.0, 2.0;
416 3.0, 4.0;
417 5.0, 6.0;
418 ];
419 let exp = matrix![
420 22.0, 28.0;
421 49.0, 64.0;
422 ];
423 assert_eq!(m * m2, exp);
424 }
425}