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