concision_core/traits/
norm.rs

1/*
2    Appellation: norm <module>
3    Contrib: @FL03
4*/
5/// a trait for computing the L1 norm of a tensor or array
6pub trait L1Norm {
7    type Output;
8
9    fn l1_norm(&self) -> Self::Output;
10}
11/// a trait for computing the L2 norm of a tensor or array
12pub trait L2Norm {
13    type Output;
14
15    fn l2_norm(&self) -> Self::Output;
16}
17
18pub trait Norm {
19    type Output;
20    /// compute the L1 norm of the tensor or array
21    fn l1_norm(&self) -> Self::Output;
22    /// compute the L2 norm of the tensor or array
23    fn l2_norm(&self) -> Self::Output;
24}
25
26/*
27 ************* Implementations *************
28*/
29use ndarray::{ArrayBase, Data, Dimension, ScalarOperand};
30use num_traits::Float;
31
32impl<U, V> Norm for U
33where
34    U: L1Norm<Output = V> + L2Norm<Output = V>,
35{
36    type Output = V;
37
38    fn l1_norm(&self) -> Self::Output {
39        <Self as L1Norm>::l1_norm(self)
40    }
41
42    fn l2_norm(&self) -> Self::Output {
43        <Self as L2Norm>::l2_norm(self)
44    }
45}
46
47macro_rules! impl_norm {
48    ($trait:ident::$method:ident($($param:ident: $type:ty),*) => $self:ident$(.$call:ident())*) => {
49        impl<A, S, D> $trait for ArrayBase<S, D>
50        where
51            A: Float + ScalarOperand,
52            D: Dimension,
53            S: Data<Elem = A>,
54        {
55            type Output = A;
56
57            fn $method(&self, $($param: $type),*) -> Self::Output {
58                self$(.$call())*
59            }
60        }
61
62        impl<'a, A, S, D> $trait for &'a ArrayBase<S, D>
63        where
64            A: Float + ScalarOperand,
65            D: Dimension,
66            S: Data<Elem = A>,
67        {
68            type Output = A;
69
70            fn $method(&self, $($param: $type),*) -> Self::Output {
71                self$(.$call())*
72            }
73        }
74
75        impl<'a, A, S, D> $trait for &'a mut ArrayBase<S, D>
76        where
77            A: Float + ScalarOperand,
78            D: Dimension,
79            S: Data<Elem = A>,
80        {
81            type Output = A;
82
83            fn $method(&self, $($param: $type),*) -> Self::Output {
84                self$(.$call())*
85            }
86        }
87    };
88}
89
90impl_norm! { L2Norm::l2_norm() => self.pow2().sum().sqrt() }
91
92impl_norm! { L1Norm::l1_norm() => self.abs().sum() }