stack_algebra/
ops.rs

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
11////////////////////////////////////////////////////////////////////////////////
12// Indexing
13////////////////////////////////////////////////////////////////////////////////
14
15impl<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
37////////////////////////////////////////////////////////////////////////////////
38// Matrix + T
39////////////////////////////////////////////////////////////////////////////////
40
41macro_rules! impl_op_scalar {
42    ($trt:ident, $meth:ident) => {
43        // Matrix + T
44        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        // Matrix + &T
60        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        // &Matrix + T
76        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        // &Matrix + &T
93        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
117////////////////////////////////////////////////////////////////////////////////
118// Matrix += T
119////////////////////////////////////////////////////////////////////////////////
120
121macro_rules! impl_op_assign_scalar {
122    ($trt:ident, $meth:ident) => {
123        // Matrix += T
124        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        // Matrix += &T
137        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
157////////////////////////////////////////////////////////////////////////////////
158// Matrix + Matrix
159////////////////////////////////////////////////////////////////////////////////
160
161macro_rules! impl_op {
162    ($trt:ident, $meth:ident) => {
163        // Matrix + Matrix
164        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        // Matrix + &Matrix
180        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        // &Matrix + Matrix
196        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        // &Matrix + &Matrix
213        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
234////////////////////////////////////////////////////////////////////////////////
235// Matrix * Matrix
236////////////////////////////////////////////////////////////////////////////////
237
238macro_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
264////////////////////////////////////////////////////////////////////////////////
265// Matrix += Matrix
266////////////////////////////////////////////////////////////////////////////////
267
268macro_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
289////////////////////////////////////////////////////////////////////////////////
290// -Matrix
291////////////////////////////////////////////////////////////////////////////////
292
293macro_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}