argmin_math/nalgebra_m/
sub.rs

1// Copyright 2018-2024 argmin developers
2//
3// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
4// http://apache.org/licenses/LICENSE-2.0> or the MIT license <LICENSE-MIT or
5// http://opensource.org/licenses/MIT>, at your option. This file may not be
6// copied, modified, or distributed except according to those terms.
7
8use std::ops::Sub;
9
10use crate::{Allocator, ArgminSub};
11
12use crate::ClosedSub;
13use nalgebra::{
14    base::{dimension::Dim, storage::Storage, Scalar},
15    DefaultAllocator, Matrix, OMatrix,
16};
17
18impl<N, R, C, S> ArgminSub<N, OMatrix<N, R, C>> for Matrix<N, R, C, S>
19where
20    N: Scalar + Copy + Sub<Output = N>,
21    R: Dim,
22    C: Dim,
23    S: Storage<N, R, C>,
24    DefaultAllocator: Allocator<N, R, C>,
25{
26    #[inline]
27    fn sub(&self, other: &N) -> OMatrix<N, R, C> {
28        self.map(|entry| entry - *other)
29    }
30}
31
32impl<N, R, C, S> ArgminSub<Matrix<N, R, C, S>, OMatrix<N, R, C>> for N
33where
34    N: Scalar + Copy + Sub<Output = N>,
35    R: Dim,
36    C: Dim,
37    S: Storage<N, R, C>,
38    DefaultAllocator: Allocator<N, R, C>,
39{
40    #[inline]
41    fn sub(&self, other: &Matrix<N, R, C, S>) -> OMatrix<N, R, C> {
42        other.map(|entry| *self - entry)
43    }
44}
45
46impl<N, R, C, S> ArgminSub<Matrix<N, R, C, S>, OMatrix<N, R, C>> for Matrix<N, R, C, S>
47where
48    N: Scalar + ClosedSub,
49    R: Dim,
50    C: Dim,
51    S: Storage<N, R, C>,
52    DefaultAllocator: Allocator<N, R, C>,
53{
54    #[inline]
55    fn sub(&self, other: &Matrix<N, R, C, S>) -> OMatrix<N, R, C> {
56        self - other
57    }
58}
59
60#[cfg(test)]
61mod tests {
62    use super::*;
63    use approx::assert_relative_eq;
64    use nalgebra::{Matrix2x3, Vector3};
65    use paste::item;
66
67    macro_rules! make_test {
68        ($t:ty) => {
69            item! {
70                #[test]
71                fn [<test_sub_vec_scalar_ $t>]() {
72                    let a = Vector3::new(36 as $t, 39 as $t, 43 as $t);
73                    let b = 1 as $t;
74                    let target = Vector3::new(35 as $t, 38 as $t, 42 as $t);
75                    let res = <Vector3<$t> as ArgminSub<$t, Vector3<$t>>>::sub(&a, &b);
76                    for i in 0..3 {
77                        assert_relative_eq!(target[i] as f64, res[i] as f64, epsilon = f64::EPSILON);
78                    }
79                }
80            }
81
82            item! {
83                #[test]
84                fn [<test_sub_scalar_vec_ $t>]() {
85                    let a = Vector3::new(1 as $t, 4 as $t, 8 as $t);
86                    let b = 34 as $t;
87                    let target = Vector3::new(33 as $t, 30 as $t, 26 as $t);
88                    let res = <$t as ArgminSub<Vector3<$t>, Vector3<$t>>>::sub(&b, &a);
89                    for i in 0..3 {
90                        assert_relative_eq!(target[i] as f64, res[i] as f64, epsilon = f64::EPSILON);
91                    }
92                }
93            }
94
95            item! {
96                #[test]
97                fn [<test_sub_vec_vec_ $t>]() {
98                    let a = Vector3::new(41 as $t, 38 as $t, 34 as $t);
99                    let b = Vector3::new(1 as $t, 4 as $t, 8 as $t);
100                    let target =Vector3::new(40 as $t, 34 as $t, 26 as $t);
101                    let res = <Vector3<$t> as ArgminSub<Vector3<$t>, Vector3<$t>>>::sub(&a, &b);
102                    for i in 0..3 {
103                        assert_relative_eq!(target[i] as f64, res[i] as f64, epsilon = f64::EPSILON);
104                    }
105                }
106            }
107
108            item! {
109                #[test]
110                fn [<test_sub_mat_mat_ $t>]() {
111                    let a = Matrix2x3::new(
112                        43 as $t, 46 as $t, 50 as $t,
113                        44 as $t, 47 as $t, 51 as $t
114                    );
115                    let b = Matrix2x3::new(
116                        1 as $t, 4 as $t, 8 as $t,
117                        2 as $t, 5 as $t, 9 as $t
118                    );
119                    let target = Matrix2x3::new(
120                        42 as $t, 42 as $t, 42 as $t,
121                        42 as $t, 42 as $t, 42 as $t
122                    );
123                    let res = <Matrix2x3<$t> as ArgminSub<Matrix2x3<$t>, Matrix2x3<$t>>>::sub(&a, &b);
124                    for i in 0..3 {
125                        for j in 0..2 {
126                            assert_relative_eq!(target[(j, i)] as f64, res[(j, i)] as f64, epsilon = f64::EPSILON);
127                        }
128                    }
129                }
130            }
131
132            item! {
133                #[test]
134                fn [<test_sub_mat_scalar_ $t>]() {
135                    let a = Matrix2x3::new(
136                        43 as $t, 46 as $t, 50 as $t,
137                        44 as $t, 47 as $t, 51 as $t
138                    );
139                    let b = 2 as $t;
140                    let target = Matrix2x3::new(
141                        41 as $t, 44 as $t, 48 as $t,
142                        42 as $t, 45 as $t, 49 as $t
143                    );
144                    let res = <Matrix2x3<$t> as ArgminSub<$t, Matrix2x3<$t>>>::sub(&a, &b);
145                    for i in 0..3 {
146                        for j in 0..2 {
147                            assert_relative_eq!(target[(j, i)] as f64, res[(j, i)] as f64, epsilon = f64::EPSILON);
148                        }
149                    }
150                }
151            }
152        };
153    }
154
155    make_test!(i8);
156    make_test!(u8);
157    make_test!(i16);
158    make_test!(u16);
159    make_test!(i32);
160    make_test!(u32);
161    make_test!(i64);
162    make_test!(u64);
163    make_test!(f32);
164    make_test!(f64);
165}