conflux/core/math/
norm_ndarray.rs

1use crate::core::math::FPNorm;
2use ndarray::Array1;
3use num::integer::Roots;
4use num_complex::Complex;
5
6macro_rules! make_norm_float {
7    ($t:ty) => {
8        impl FPNorm<$t> for Array1<$t> {
9            #[inline]
10            fn norm(&self) -> $t {
11                self.iter().map(|x| x.powi(2)).sum::<$t>().sqrt()
12            }
13        }
14    };
15}
16
17macro_rules! make_norm_complex_float {
18    ($t:ty) => {
19        impl FPNorm<Complex<$t>> for Array1<Complex<$t>> {
20            #[inline]
21            fn norm(&self) -> Complex<$t> {
22                self.iter().map(|a| a.powf(2.0)).sum::<Complex<$t>>().sqrt()
23            }
24        }
25
26        impl FPNorm<$t> for Array1<Complex<$t>> {
27            #[inline]
28            fn norm(&self) -> $t {
29                self.iter()
30                    .map(|a| a.powf(2.0))
31                    .sum::<Complex<$t>>()
32                    .sqrt()
33                    .norm()
34            }
35        }
36    };
37}
38
39macro_rules! make_norm_integer {
40    ($t:ty) => {
41        impl FPNorm<$t> for Array1<$t> {
42            #[inline]
43            fn norm(&self) -> $t {
44                self.iter().map(|a| a.pow(2)).sum::<$t>().sqrt()
45            }
46        }
47    };
48}
49
50make_norm_integer!(isize);
51make_norm_integer!(usize);
52make_norm_integer!(i8);
53make_norm_integer!(i16);
54make_norm_integer!(i32);
55make_norm_integer!(i64);
56make_norm_integer!(u8);
57make_norm_integer!(u16);
58make_norm_integer!(u32);
59make_norm_integer!(u64);
60make_norm_float!(f32);
61make_norm_float!(f64);
62make_norm_complex_float!(f32);
63make_norm_complex_float!(f64);
64
65#[cfg(test)]
66mod tests {
67    use super::*;
68    use ndarray::{array, Array1};
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 = array![4 as $t, 3 as $t];
77                    let res = <Array1<$t> as FPNorm<$t>>::norm(&a);
78                    let target = 5 as $t;
79                    assert!(((target - res) as f64).abs() < std::f64::EPSILON);
80                }
81            }
82        };
83    }
84
85    macro_rules! make_test_signed {
86        ($t:ty) => {
87            item! {
88                #[test]
89                fn [<test_norm_signed_ $t>]() {
90                    let a = array![-4 as $t, -3 as $t];
91                    let res = <Array1<$t> as FPNorm<$t>>::norm(&a);
92                    let target = 5 as $t;
93                    assert!(((target - res) as f64).abs() < std::f64::EPSILON);
94                }
95            }
96        };
97    }
98
99    make_test!(isize);
100    make_test!(usize);
101    make_test!(i8);
102    make_test!(u8);
103    make_test!(i16);
104    make_test!(u16);
105    make_test!(i32);
106    make_test!(u32);
107    make_test!(i64);
108    make_test!(u64);
109    make_test!(f32);
110    make_test!(f64);
111
112    make_test_signed!(isize);
113    make_test_signed!(i8);
114    make_test_signed!(i16);
115    make_test_signed!(i32);
116    make_test_signed!(i64);
117    make_test_signed!(f32);
118    make_test_signed!(f64);
119}