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 |