Tue, 31 Dec 2024 08:30:02 -0500
Significantly simplify Mapping / Apply through Instance
0 | 1 | /*! |
2 | Norms, projections, etc. | |
3 | */ | |
4 | ||
5 | 5 | use serde::Serialize; |
59
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
6 | use std::marker::PhantomData; |
0 | 7 | use crate::types::*; |
5 | 8 | use crate::euclidean::*; |
59
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
9 | use crate::mapping::{Mapping, Space, Instance}; |
0 | 10 | |
11 | // | |
12 | // Abstract norms | |
13 | // | |
14 | ||
59
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
15 | #[derive(Copy,Clone,Debug)] |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
16 | /// Helper structure to convert a [`NormExponent`] into a [`Mapping`] |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
17 | pub struct NormMapping<F : Float, E : NormExponent>{ |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
18 | pub(crate) exponent : E, |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
19 | _phantoms : PhantomData<F> |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
20 | } |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
21 | |
6
d80b87b8acd0
Added NormExponent trait for exponents of norms
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
22 | /// An exponent for norms. |
d80b87b8acd0
Added NormExponent trait for exponents of norms
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
23 | /// |
33 | 24 | // Just a collection of desirable attributes for a marker type |
59
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
25 | pub trait NormExponent : Copy + Send + Sync + 'static { |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
26 | /// Return the norm as a mappin |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
27 | fn as_mapping<F : Float>(self) -> NormMapping<F, Self> { |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
28 | NormMapping{ exponent : self, _phantoms : PhantomData } |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
29 | } |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
30 | } |
6
d80b87b8acd0
Added NormExponent trait for exponents of norms
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
31 | |
5 | 32 | /// Exponent type for the 1-[`Norm`]. |
0 | 33 | #[derive(Copy,Debug,Clone,Serialize,Eq,PartialEq)] |
34 | pub struct L1; | |
6
d80b87b8acd0
Added NormExponent trait for exponents of norms
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
35 | impl NormExponent for L1 {} |
0 | 36 | |
5 | 37 | /// Exponent type for the 2-[`Norm`]. |
0 | 38 | #[derive(Copy,Debug,Clone,Serialize,Eq,PartialEq)] |
39 | pub struct L2; | |
6
d80b87b8acd0
Added NormExponent trait for exponents of norms
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
40 | impl NormExponent for L2 {} |
0 | 41 | |
5 | 42 | /// Exponent type for the ∞-[`Norm`]. |
0 | 43 | #[derive(Copy,Debug,Clone,Serialize,Eq,PartialEq)] |
44 | pub struct Linfinity; | |
6
d80b87b8acd0
Added NormExponent trait for exponents of norms
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
45 | impl NormExponent for Linfinity {} |
0 | 46 | |
5 | 47 | /// Exponent type for 2,1-[`Norm`]. |
48 | /// (1-norm over a domain Ω, 2-norm of a vector at each point of the domain.) | |
0 | 49 | #[derive(Copy,Debug,Clone,Serialize,Eq,PartialEq)] |
50 | pub struct L21; | |
6
d80b87b8acd0
Added NormExponent trait for exponents of norms
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
51 | impl NormExponent for L21 {} |
0 | 52 | |
59
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
53 | /// Norms for pairs (a, b). ‖(a,b)‖ = ‖(‖a‖_A, ‖b‖_B)‖_J |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
54 | /// For use with [`crate::direct_product::Pair`] |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
55 | #[derive(Copy,Debug,Clone,Serialize,Eq,PartialEq)] |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
56 | pub struct PairNorm<A, B, J>(pub A, pub B, pub J); |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
57 | |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
58 | impl<A, B, J> NormExponent for PairNorm<A, B, J> |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
59 | where A : NormExponent, B : NormExponent, J : NormExponent {} |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
60 | |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
61 | |
5 | 62 | /// A Huber/Moreau–Yosida smoothed [`L1`] norm. (Not a norm itself.) |
63 | /// | |
64 | /// The parameter γ of this type is the smoothing factor. Zero means no smoothing, and higher | |
65 | /// values more smoothing. Behaviour with γ < 0 is undefined. | |
0 | 66 | #[derive(Copy,Debug,Clone,Serialize,Eq,PartialEq)] |
67 | pub struct HuberL1<F : Float>(pub F); | |
6
d80b87b8acd0
Added NormExponent trait for exponents of norms
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
68 | impl<F : Float> NormExponent for HuberL1<F> {} |
0 | 69 | |
5 | 70 | /// A Huber/Moreau–Yosida smoothed [`L21`] norm. (Not a norm itself.) |
71 | /// | |
72 | /// The parameter γ of this type is the smoothing factor. Zero means no smoothing, and higher | |
73 | /// values more smoothing. Behaviour with γ < 0 is undefined. | |
0 | 74 | #[derive(Copy,Debug,Clone,Serialize,Eq,PartialEq)] |
75 | pub struct HuberL21<F : Float>(pub F); | |
6
d80b87b8acd0
Added NormExponent trait for exponents of norms
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
76 | impl<F : Float> NormExponent for HuberL21<F> {} |
d80b87b8acd0
Added NormExponent trait for exponents of norms
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
77 | |
0 | 78 | |
5 | 79 | /// A normed space (type) with exponent or other type `Exponent` for the norm. |
80 | /// | |
81 | /// Use as | |
82 | /// ``` | |
83 | /// # use alg_tools::norms::{Norm, L1, L2, Linfinity}; | |
84 | /// # use alg_tools::loc::Loc; | |
85 | /// let x = Loc([1.0, 2.0, 3.0]); | |
86 | /// | |
87 | /// println!("{}, {} {}", x.norm(L1), x.norm(L2), x.norm(Linfinity)) | |
88 | /// ``` | |
6
d80b87b8acd0
Added NormExponent trait for exponents of norms
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
89 | pub trait Norm<F : Num, Exponent : NormExponent> { |
5 | 90 | /// Calculate the norm. |
0 | 91 | fn norm(&self, _p : Exponent) -> F; |
92 | } | |
93 | ||
5 | 94 | /// Indicates that the `Self`-[`Norm`] is dominated by the `Exponent`-`Norm` on the space |
95 | /// `Elem` with the corresponding field `F`. | |
6
d80b87b8acd0
Added NormExponent trait for exponents of norms
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
96 | pub trait Dominated<F : Num, Exponent : NormExponent, Elem> { |
0 | 97 | /// Indicates the factor $c$ for the inequality $‖x‖ ≤ C ‖x‖_p$. |
98 | fn norm_factor(&self, p : Exponent) -> F; | |
99 | /// Given a norm-value $‖x‖_p$, calculates $C‖x‖_p$ such that $‖x‖ ≤ C‖x‖_p$ | |
100 | #[inline] | |
101 | fn from_norm(&self, p_norm : F, p : Exponent) -> F { | |
102 | p_norm * self.norm_factor(p) | |
103 | } | |
104 | } | |
105 | ||
5 | 106 | /// Trait for distances with respect to a norm. |
6
d80b87b8acd0
Added NormExponent trait for exponents of norms
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
107 | pub trait Dist<F : Num, Exponent : NormExponent> : Norm<F, Exponent> { |
0 | 108 | /// Calculate the distance |
109 | fn dist(&self, other : &Self, _p : Exponent) -> F; | |
110 | } | |
111 | ||
5 | 112 | /// Trait for Euclidean projections to the `Exponent`-[`Norm`]-ball. |
113 | /// | |
114 | /// Use as | |
115 | /// ``` | |
116 | /// # use alg_tools::norms::{Projection, L2, Linfinity}; | |
117 | /// # use alg_tools::loc::Loc; | |
118 | /// let x = Loc([1.0, 2.0, 3.0]); | |
119 | /// | |
120 | /// println!("{:?}, {:?}", x.proj_ball(1.0, L2), x.proj_ball(0.5, Linfinity)); | |
121 | /// ``` | |
6
d80b87b8acd0
Added NormExponent trait for exponents of norms
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
122 | pub trait Projection<F : Num, Exponent : NormExponent> : Norm<F, Exponent> + Euclidean<F> |
d80b87b8acd0
Added NormExponent trait for exponents of norms
Tuomo Valkonen <tuomov@iki.fi>
parents:
5
diff
changeset
|
123 | where F : Float { |
5 | 124 | /// Projection of `self` to the `q`-norm-ball of radius ρ. |
0 | 125 | fn proj_ball(mut self, ρ : F, q : Exponent) -> Self { |
126 | self.proj_ball_mut(ρ, q); | |
127 | self | |
128 | } | |
129 | ||
5 | 130 | /// In-place projection of `self` to the `q`-norm-ball of radius ρ. |
0 | 131 | fn proj_ball_mut(&mut self, ρ : F, _q : Exponent); |
132 | } | |
133 | ||
134 | /*impl<F : Float, E : Euclidean<F>> Norm<F, L2> for E { | |
135 | #[inline] | |
136 | fn norm(&self, _p : L2) -> F { self.norm2() } | |
137 | ||
138 | fn dist(&self, other : &Self, _p : L2) -> F { self.dist2(other) } | |
139 | }*/ | |
140 | ||
141 | impl<F : Float, E : Euclidean<F> + Norm<F, L2>> Projection<F, L2> for E { | |
142 | #[inline] | |
143 | fn proj_ball(self, ρ : F, _p : L2) -> Self { self.proj_ball2(ρ) } | |
144 | ||
145 | #[inline] | |
146 | fn proj_ball_mut(&mut self, ρ : F, _p : L2) { self.proj_ball2_mut(ρ) } | |
147 | } | |
148 | ||
149 | impl<F : Float> HuberL1<F> { | |
150 | fn apply(self, xnsq : F) -> F { | |
151 | let HuberL1(γ) = self; | |
152 | let xn = xnsq.sqrt(); | |
153 | if γ == F::ZERO { | |
154 | xn | |
155 | } else { | |
156 | if xn > γ { | |
5 | 157 | xn-γ / F::TWO |
0 | 158 | } else if xn<(-γ) { |
5 | 159 | -xn-γ / F::TWO |
0 | 160 | } else { |
5 | 161 | xnsq / (F::TWO * γ) |
0 | 162 | } |
163 | } | |
164 | } | |
165 | } | |
166 | ||
167 | impl<F : Float, E : Euclidean<F>> Norm<F, HuberL1<F>> for E { | |
168 | fn norm(&self, huber : HuberL1<F>) -> F { | |
169 | huber.apply(self.norm2_squared()) | |
170 | } | |
171 | } | |
172 | ||
173 | impl<F : Float, E : Euclidean<F>> Dist<F, HuberL1<F>> for E { | |
174 | fn dist(&self, other : &Self, huber : HuberL1<F>) -> F { | |
175 | huber.apply(self.dist2_squared(other)) | |
176 | } | |
177 | } | |
178 | ||
59
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
179 | impl<F : Float, E : Norm<F, L2>> Norm<F, L21> for Vec<E> { |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
180 | fn norm(&self, _l21 : L21) -> F { |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
181 | self.iter().map(|e| e.norm(L2)).sum() |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
182 | } |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
183 | } |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
184 | |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
185 | impl<F : Float, E : Dist<F, L2>> Dist<F, L21> for Vec<E> { |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
186 | fn dist(&self, other : &Self, _l21 : L21) -> F { |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
187 | self.iter().zip(other.iter()).map(|(e, g)| e.dist(g, L2)).sum() |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
188 | } |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
189 | } |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
190 | |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
191 | impl<E, F, Domain> Mapping<Domain> for NormMapping<F, E> |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
192 | where |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
193 | F : Float, |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
194 | E : NormExponent, |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
195 | Domain : Space + Norm<F, E>, |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
196 | { |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
197 | type Codomain = F; |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
198 | |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
199 | #[inline] |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
200 | fn apply<I : Instance<Domain>>(&self, x : I) -> F { |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
201 | x.eval(|r| r.norm(self.exponent)) |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
202 | } |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
203 | } |
9226980e45a7
Significantly simplify Mapping / Apply through Instance
Tuomo Valkonen <tuomov@iki.fi>
parents:
33
diff
changeset
|
204 |