src/norms.rs

changeset 90
b3c35d16affe
parent 72
44a4f258a1ff
child 86
d5b0e496b72f
equal deleted inserted replaced
25:d14c877e14b7 90:b3c35d16affe
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.
80 p_norm * self.norm_factor(p) 102 p_norm * self.norm_factor(p)
81 } 103 }
82 } 104 }
83 105
84 /// Trait for distances with respect to a norm. 106 /// Trait for distances with respect to a norm.
85 pub trait Dist<F : Num, Exponent : NormExponent> : Norm<F, Exponent> { 107 pub trait Dist<F : Num, Exponent : NormExponent> : Norm<F, Exponent> + Space {
86 /// Calculate the distance 108 /// Calculate the distance
87 fn dist(&self, other : &Self, _p : Exponent) -> F; 109 fn dist<I : Instance<Self>>(&self, other : I, _p : Exponent) -> F;
88 } 110 }
89 111
90 /// Trait for Euclidean projections to the `Exponent`-[`Norm`]-ball. 112 /// Trait for Euclidean projections to the `Exponent`-[`Norm`]-ball.
91 /// 113 ///
92 /// Use as 114 /// Use as
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

mercurial