| 1 /*! |
1 /*! |
| 2 Norms, projections, etc. |
2 Norms, projections, etc. |
| 3 */ |
3 */ |
| 4 |
4 |
| 5 use serde::Serialize; |
5 use serde::Serialize; |
| |
6 use std::marker::PhantomData; |
| 6 use crate::types::*; |
7 use crate::types::*; |
| 7 use crate::euclidean::*; |
8 use crate::euclidean::*; |
| |
9 use crate::mapping::{Mapping, Space, Instance}; |
| 8 |
10 |
| 9 // |
11 // |
| 10 // Abstract norms |
12 // Abstract norms |
| 11 // |
13 // |
| 12 |
14 |
| |
15 #[derive(Copy,Clone,Debug)] |
| |
16 /// Helper structure to convert a [`NormExponent`] into a [`Mapping`] |
| |
17 pub struct NormMapping<F : Float, E : NormExponent>{ |
| |
18 pub(crate) exponent : E, |
| |
19 _phantoms : PhantomData<F> |
| |
20 } |
| |
21 |
| 13 /// An exponent for norms. |
22 /// An exponent for norms. |
| 14 /// |
23 /// |
| 15 // Just a collection of desirabl attributes for a marker type |
24 // Just a collection of desirable attributes for a marker type |
| 16 pub trait NormExponent : Copy + Send + Sync + 'static {} |
25 pub trait NormExponent : Copy + Send + Sync + 'static { |
| 17 |
26 /// Return the norm as a mappin |
| |
27 fn as_mapping<F : Float>(self) -> NormMapping<F, Self> { |
| |
28 NormMapping{ exponent : self, _phantoms : PhantomData } |
| |
29 } |
| |
30 } |
| 18 |
31 |
| 19 /// Exponent type for the 1-[`Norm`]. |
32 /// Exponent type for the 1-[`Norm`]. |
| 20 #[derive(Copy,Debug,Clone,Serialize,Eq,PartialEq)] |
33 #[derive(Copy,Debug,Clone,Serialize,Eq,PartialEq)] |
| 21 pub struct L1; |
34 pub struct L1; |
| 22 impl NormExponent for L1 {} |
35 impl NormExponent for L1 {} |
| 34 /// Exponent type for 2,1-[`Norm`]. |
47 /// Exponent type for 2,1-[`Norm`]. |
| 35 /// (1-norm over a domain Ω, 2-norm of a vector at each point of the domain.) |
48 /// (1-norm over a domain Ω, 2-norm of a vector at each point of the domain.) |
| 36 #[derive(Copy,Debug,Clone,Serialize,Eq,PartialEq)] |
49 #[derive(Copy,Debug,Clone,Serialize,Eq,PartialEq)] |
| 37 pub struct L21; |
50 pub struct L21; |
| 38 impl NormExponent for L21 {} |
51 impl NormExponent for L21 {} |
| |
52 |
| |
53 /// Norms for pairs (a, b). ‖(a,b)‖ = ‖(‖a‖_A, ‖b‖_B)‖_J |
| |
54 /// For use with [`crate::direct_product::Pair`] |
| |
55 #[derive(Copy,Debug,Clone,Serialize,Eq,PartialEq)] |
| |
56 pub struct PairNorm<A, B, J>(pub A, pub B, pub J); |
| |
57 |
| |
58 impl<A, B, J> NormExponent for PairNorm<A, B, J> |
| |
59 where A : NormExponent, B : NormExponent, J : NormExponent {} |
| |
60 |
| 39 |
61 |
| 40 /// A Huber/Moreau–Yosida smoothed [`L1`] norm. (Not a norm itself.) |
62 /// A Huber/Moreau–Yosida smoothed [`L1`] norm. (Not a norm itself.) |
| 41 /// |
63 /// |
| 42 /// The parameter γ of this type is the smoothing factor. Zero means no smoothing, and higher |
64 /// The parameter γ of this type is the smoothing factor. Zero means no smoothing, and higher |
| 43 /// values more smoothing. Behaviour with γ < 0 is undefined. |
65 /// values more smoothing. Behaviour with γ < 0 is undefined. |
| 95 /// # use alg_tools::loc::Loc; |
117 /// # use alg_tools::loc::Loc; |
| 96 /// let x = Loc([1.0, 2.0, 3.0]); |
118 /// let x = Loc([1.0, 2.0, 3.0]); |
| 97 /// |
119 /// |
| 98 /// println!("{:?}, {:?}", x.proj_ball(1.0, L2), x.proj_ball(0.5, Linfinity)); |
120 /// println!("{:?}, {:?}", x.proj_ball(1.0, L2), x.proj_ball(0.5, Linfinity)); |
| 99 /// ``` |
121 /// ``` |
| 100 pub trait Projection<F : Num, Exponent : NormExponent> : Norm<F, Exponent> + Euclidean<F> |
122 pub trait Projection<F : Num, Exponent : NormExponent> : Norm<F, Exponent> + Sized |
| 101 where F : Float { |
123 where F : Float { |
| 102 /// Projection of `self` to the `q`-norm-ball of radius ρ. |
124 /// Projection of `self` to the `q`-norm-ball of radius ρ. |
| 103 fn proj_ball(mut self, ρ : F, q : Exponent) -> Self { |
125 fn proj_ball(mut self, ρ : F, q : Exponent) -> Self { |
| 104 self.proj_ball_mut(ρ, q); |
126 self.proj_ball_mut(ρ, q); |
| 105 self |
127 self |
| 106 } |
128 } |
| 107 |
129 |
| 108 /// In-place projection of `self` to the `q`-norm-ball of radius ρ. |
130 /// In-place projection of `self` to the `q`-norm-ball of radius ρ. |
| 109 fn proj_ball_mut(&mut self, ρ : F, _q : Exponent); |
131 fn proj_ball_mut(&mut self, ρ : F, q : Exponent); |
| 110 } |
132 } |
| 111 |
133 |
| 112 /*impl<F : Float, E : Euclidean<F>> Norm<F, L2> for E { |
134 /*impl<F : Float, E : Euclidean<F>> Norm<F, L2> for E { |
| 113 #[inline] |
135 #[inline] |
| 114 fn norm(&self, _p : L2) -> F { self.norm2() } |
136 fn norm(&self, _p : L2) -> F { self.norm2() } |
| 147 huber.apply(self.norm2_squared()) |
169 huber.apply(self.norm2_squared()) |
| 148 } |
170 } |
| 149 } |
171 } |
| 150 |
172 |
| 151 impl<F : Float, E : Euclidean<F>> Dist<F, HuberL1<F>> for E { |
173 impl<F : Float, E : Euclidean<F>> Dist<F, HuberL1<F>> for E { |
| 152 fn dist(&self, other : &Self, huber : HuberL1<F>) -> F { |
174 fn dist<I : Instance<Self>>(&self, other : I, huber : HuberL1<F>) -> F { |
| 153 huber.apply(self.dist2_squared(other)) |
175 huber.apply(self.dist2_squared(other)) |
| 154 } |
176 } |
| 155 } |
177 } |
| 156 |
178 |
| |
179 // impl<F : Float, E : Norm<F, L2>> Norm<F, L21> for Vec<E> { |
| |
180 // fn norm(&self, _l21 : L21) -> F { |
| |
181 // self.iter().map(|e| e.norm(L2)).sum() |
| |
182 // } |
| |
183 // } |
| |
184 |
| |
185 // impl<F : Float, E : Dist<F, L2>> Dist<F, L21> for Vec<E> { |
| |
186 // fn dist<I : Instance<Self>>(&self, other : I, _l21 : L21) -> F { |
| |
187 // self.iter().zip(other.iter()).map(|(e, g)| e.dist(g, L2)).sum() |
| |
188 // } |
| |
189 // } |
| |
190 |
| |
191 impl<E, F, Domain> Mapping<Domain> for NormMapping<F, E> |
| |
192 where |
| |
193 F : Float, |
| |
194 E : NormExponent, |
| |
195 Domain : Space + Norm<F, E>, |
| |
196 { |
| |
197 type Codomain = F; |
| |
198 |
| |
199 #[inline] |
| |
200 fn apply<I : Instance<Domain>>(&self, x : I) -> F { |
| |
201 x.eval(|r| r.norm(self.exponent)) |
| |
202 } |
| |
203 } |
| |
204 |
| |
205 pub trait Normed<F : Num = f64> : Space + Norm<F, Self::NormExp> { |
| |
206 type NormExp : NormExponent; |
| |
207 |
| |
208 fn norm_exponent(&self) -> Self::NormExp; |
| |
209 |
| |
210 #[inline] |
| |
211 fn norm_(&self) -> F { |
| |
212 self.norm(self.norm_exponent()) |
| |
213 } |
| |
214 |
| |
215 // fn similar_origin(&self) -> Self; |
| |
216 |
| |
217 fn is_zero(&self) -> bool; |
| |
218 } |
| |
219 |
| |
220 pub trait HasDual<F : Num = f64> : Normed<F> { |
| |
221 type DualSpace : Normed<F>; |
| |
222 } |
| |
223 |
| |
224 /// Automatically implemented trait for reflexive spaces |
| |
225 pub trait Reflexive<F : Num = f64> : HasDual<F> |
| |
226 where |
| |
227 Self::DualSpace : HasDual<F, DualSpace = Self> |
| |
228 { } |
| |
229 |
| |
230 impl<F : Num, X : HasDual<F>> Reflexive<F> for X |
| |
231 where |
| |
232 X::DualSpace : HasDual<F, DualSpace = X> |
| |
233 { } |
| |
234 |
| |
235 pub trait HasDualExponent : NormExponent { |
| |
236 type DualExp : NormExponent; |
| |
237 |
| |
238 fn dual_exponent(&self) -> Self::DualExp; |
| |
239 } |
| |
240 |
| |
241 impl HasDualExponent for L2 { |
| |
242 type DualExp = L2; |
| |
243 |
| |
244 #[inline] |
| |
245 fn dual_exponent(&self) -> Self::DualExp { |
| |
246 L2 |
| |
247 } |
| |
248 } |
| |
249 |
| |
250 impl HasDualExponent for L1 { |
| |
251 type DualExp = Linfinity; |
| |
252 |
| |
253 #[inline] |
| |
254 fn dual_exponent(&self) -> Self::DualExp { |
| |
255 Linfinity |
| |
256 } |
| |
257 } |
| |
258 |
| |
259 |
| |
260 impl HasDualExponent for Linfinity { |
| |
261 type DualExp = L1; |
| |
262 |
| |
263 #[inline] |
| |
264 fn dual_exponent(&self) -> Self::DualExp { |
| |
265 L1 |
| |
266 } |
| |
267 } |
| |
268 |
| |
269 #[macro_export] |
| |
270 macro_rules! impl_weighted_norm { |
| |
271 ($exponent : ty) => { |
| |
272 impl<C, F, D> Norm<F, Weighted<$exponent, C>> for D |
| |
273 where |
| |
274 F : Float, |
| |
275 D : Norm<F, $exponent>, |
| |
276 C : Constant<Type = F>, |
| |
277 { |
| |
278 fn norm(&self, e : Weighted<$exponent, C>) -> F { |
| |
279 let v = e.weight.value(); |
| |
280 assert!(v > F::ZERO); |
| |
281 v * self.norm(e.base_fn) |
| |
282 } |
| |
283 } |
| |
284 |
| |
285 impl<C : Constant> NormExponent for Weighted<$exponent, C> {} |
| |
286 |
| |
287 impl<C : Constant> HasDualExponent for Weighted<$exponent, C> |
| |
288 where $exponent : HasDualExponent { |
| |
289 type DualExp = Weighted<<$exponent as HasDualExponent>::DualExp, C::Type>; |
| |
290 |
| |
291 fn dual_exponent(&self) -> Self::DualExp { |
| |
292 Weighted { |
| |
293 weight : C::Type::ONE / self.weight.value(), |
| |
294 base_fn : self.base_fn.dual_exponent() |
| |
295 } |
| |
296 } |
| |
297 } |
| |
298 |
| |
299 impl<C, F, T> Projection<F, Weighted<$exponent , C>> for T |
| |
300 where |
| |
301 T : Projection<F, $exponent >, |
| |
302 F : Float, |
| |
303 C : Constant<Type = F>, |
| |
304 { |
| |
305 fn proj_ball(self, ρ : F, q : Weighted<$exponent , C>) -> Self { |
| |
306 self.proj_ball(ρ / q.weight.value(), q.base_fn) |
| |
307 } |
| |
308 |
| |
309 fn proj_ball_mut(&mut self, ρ : F, q : Weighted<$exponent , C>) { |
| |
310 self.proj_ball_mut(ρ / q.weight.value(), q.base_fn) |
| |
311 } |
| |
312 } |
| |
313 } |
| |
314 } |
| |
315 |
| |
316 //impl_weighted_norm!(L1); |
| |
317 //impl_weighted_norm!(L2); |
| |
318 //impl_weighted_norm!(Linfinity); |
| |
319 |