argmin_math/primitives/
l2norm.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 crate::ArgminL2Norm;
9use num_complex::Complex;
10
11macro_rules! make_norm_unsigned {
12    ($t:ty) => {
13        impl ArgminL2Norm<$t> for $t {
14            #[inline]
15            fn l2_norm(&self) -> $t {
16                *self
17            }
18        }
19    };
20}
21
22macro_rules! make_norm {
23    ($t:ty) => {
24        impl ArgminL2Norm<$t> for $t {
25            #[inline]
26            fn l2_norm(&self) -> $t {
27                (*self).abs()
28            }
29        }
30    };
31}
32
33macro_rules! make_norm_complex {
34    ($t:ty) => {
35        impl ArgminL2Norm<$t> for Complex<$t> {
36            #[inline]
37            fn l2_norm(&self) -> $t {
38                (*self).re.hypot((*self).im)
39            }
40        }
41    };
42}
43
44make_norm!(i8);
45make_norm!(i16);
46make_norm!(i32);
47make_norm!(i64);
48make_norm_unsigned!(u8);
49make_norm_unsigned!(u16);
50make_norm_unsigned!(u32);
51make_norm_unsigned!(u64);
52make_norm!(f32);
53make_norm!(f64);
54
55make_norm_complex!(f32);
56make_norm_complex!(f64);
57
58#[cfg(test)]
59mod tests {
60    use super::*;
61    use approx::assert_relative_eq;
62    use paste::item;
63
64    macro_rules! make_test {
65        ($t:ty) => {
66            item! {
67                #[test]
68                fn [<test_norm_ $t>]() {
69                    let a = 8 as $t;
70                    let res = <$t as ArgminL2Norm<$t>>::l2_norm(&a);
71                    assert_relative_eq!(a as f64, res as f64, epsilon = f64::EPSILON);
72                }
73            }
74        };
75    }
76
77    macro_rules! make_test_signed {
78        ($t:ty) => {
79            item! {
80                #[test]
81                fn [<test_norm_signed_ $t>]() {
82                    let a = -8 as $t;
83                    let res = <$t as ArgminL2Norm<$t>>::l2_norm(&a);
84                    assert_relative_eq!(8 as f64, res as f64, epsilon = f64::EPSILON);
85                }
86            }
87        };
88    }
89
90    macro_rules! make_test_complex {
91        ($t:ty) => {
92            item! {
93                #[test]
94                fn [<test_norm_complex_ $t>]() {
95                    let a = Complex::new(8 as $t, 4 as $t);
96                    let res = <Complex<$t> as ArgminL2Norm<$t>>::l2_norm(&a);
97                    assert_relative_eq!((a.re.powi(2) + a.im.powi(2)).sqrt() as f64, res as f64, epsilon = f64::EPSILON);
98                }
99            }
100        };
101    }
102
103    macro_rules! make_test_complex_signed {
104        ($t:ty) => {
105            item! {
106                #[test]
107                fn [<test_norm_complex_signed_ $t>]() {
108                    let a = Complex::new(-8 as $t, -4 as $t);
109                    let res = <Complex<$t> as ArgminL2Norm<$t>>::l2_norm(&a);
110                    assert_relative_eq!((a.re.powi(2)+a.im.powi(2)).sqrt() as f64, res as f64, epsilon = f64::EPSILON);
111                }
112            }
113        };
114    }
115
116    make_test!(i8);
117    make_test!(u8);
118    make_test!(i16);
119    make_test!(u16);
120    make_test!(i32);
121    make_test!(u32);
122    make_test!(i64);
123    make_test!(u64);
124    make_test!(f32);
125    make_test!(f64);
126
127    make_test_signed!(i8);
128    make_test_signed!(i16);
129    make_test_signed!(i32);
130    make_test_signed!(i64);
131    make_test_signed!(f32);
132    make_test_signed!(f64);
133
134    make_test_complex!(f32);
135    make_test_complex!(f64);
136
137    make_test_complex_signed!(f32);
138    make_test_complex_signed!(f64);
139}