argmin_math/vec/
l1norm.rs1use 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}