| 12 Bounds, |
12 Bounds, |
| 13 LocalAnalysis, |
13 LocalAnalysis, |
| 14 GlobalAnalysis, |
14 GlobalAnalysis, |
| 15 Bounded, |
15 Bounded, |
| 16 }; |
16 }; |
| 17 use alg_tools::mapping::{Apply, Differentiable}; |
17 use alg_tools::mapping::{ |
| |
18 Mapping, |
| |
19 DifferentiableImpl, |
| |
20 DifferentiableMapping, |
| |
21 Differential, |
| |
22 }; |
| |
23 use alg_tools::instance::{Instance, Space}; |
| 18 use alg_tools::maputil::{array_init, map2, map1_indexed}; |
24 use alg_tools::maputil::{array_init, map2, map1_indexed}; |
| 19 use alg_tools::sets::SetOrd; |
25 use alg_tools::sets::SetOrd; |
| 20 |
26 |
| 21 use crate::fourier::Fourier; |
27 use crate::fourier::Fourier; |
| 22 use crate::types::Lipschitz; |
28 use crate::types::*; |
| 23 |
29 |
| 24 /// Representation of the product of two kernels. |
30 /// Representation of the product of two kernels. |
| 25 /// |
31 /// |
| 26 /// The kernels typically implement [`Support`] and [`Mapping`][alg_tools::mapping::Mapping]. |
32 /// The kernels typically implement [`Support`] and [`Mapping`]. |
| 27 /// |
33 /// |
| 28 /// The implementation [`Support`] only uses the [`Support::support_hint`] of the first parameter! |
34 /// The implementation [`Support`] only uses the [`Support::support_hint`] of the first parameter! |
| 29 #[derive(Copy,Clone,Serialize,Debug)] |
35 #[derive(Copy,Clone,Serialize,Debug)] |
| 30 pub struct SupportProductFirst<A, B>( |
36 pub struct SupportProductFirst<A, B>( |
| 31 /// First kernel |
37 /// First kernel |
| 32 pub A, |
38 pub A, |
| 33 /// Second kernel |
39 /// Second kernel |
| 34 pub B |
40 pub B |
| 35 ); |
41 ); |
| 36 |
42 |
| 37 impl<A, B, F : Float, const N : usize> Apply<Loc<F, N>> |
43 impl<A, B, F : Float, const N : usize> Mapping<Loc<F, N>> |
| 38 for SupportProductFirst<A, B> |
44 for SupportProductFirst<A, B> |
| 39 where A : for<'a> Apply<&'a Loc<F, N>, Output=F>, |
45 where |
| 40 B : for<'a> Apply<&'a Loc<F, N>, Output=F> { |
46 A : Mapping<Loc<F, N>, Codomain = F>, |
| 41 type Output = F; |
47 B : Mapping<Loc<F, N>, Codomain = F>, |
| 42 #[inline] |
48 { |
| 43 fn apply(&self, x : Loc<F, N>) -> Self::Output { |
49 type Codomain = F; |
| 44 self.0.apply(&x) * self.1.apply(&x) |
50 |
| 45 } |
51 #[inline] |
| 46 } |
52 fn apply<I : Instance<Loc<F, N>>>(&self, x : I) -> Self::Codomain { |
| 47 |
53 self.0.apply(x.ref_instance()) * self.1.apply(x) |
| 48 impl<'a, A, B, F : Float, const N : usize> Apply<&'a Loc<F, N>> |
54 } |
| |
55 } |
| |
56 |
| |
57 impl<A, B, F : Float, const N : usize> DifferentiableImpl<Loc<F, N>> |
| 49 for SupportProductFirst<A, B> |
58 for SupportProductFirst<A, B> |
| 50 where A : Apply<&'a Loc<F, N>, Output=F>, |
59 where |
| 51 B : Apply<&'a Loc<F, N>, Output=F> { |
60 A : DifferentiableMapping< |
| 52 type Output = F; |
61 Loc<F, N>, |
| 53 #[inline] |
62 DerivativeDomain=Loc<F, N>, |
| 54 fn apply(&self, x : &'a Loc<F, N>) -> Self::Output { |
63 Codomain = F |
| 55 self.0.apply(x) * self.1.apply(x) |
64 >, |
| 56 } |
65 B : DifferentiableMapping< |
| 57 } |
66 Loc<F, N>, |
| 58 |
67 DerivativeDomain=Loc<F, N>, |
| 59 impl<A, B, F : Float, const N : usize> Differentiable<Loc<F, N>> |
68 Codomain = F, |
| |
69 > |
| |
70 { |
| |
71 type Derivative = Loc<F, N>; |
| |
72 |
| |
73 #[inline] |
| |
74 fn differential_impl<I : Instance<Loc<F, N>>>(&self, x : I) -> Self::Derivative { |
| |
75 let xr = x.ref_instance(); |
| |
76 self.0.differential(xr) * self.1.apply(xr) + self.1.differential(xr) * self.0.apply(x) |
| |
77 } |
| |
78 } |
| |
79 |
| |
80 impl<A, B, M : Copy, F : Float> Lipschitz<M> |
| 60 for SupportProductFirst<A, B> |
81 for SupportProductFirst<A, B> |
| 61 where A : for<'a> Apply<&'a Loc<F, N>, Output=F> |
82 where A : Lipschitz<M, FloatType = F> + Bounded<F>, |
| 62 + for<'a> Differentiable<&'a Loc<F, N>, Output=Loc<F, N>>, |
83 B : Lipschitz<M, FloatType = F> + Bounded<F> { |
| 63 B : for<'a> Apply<&'a Loc<F, N>, Output=F> |
84 type FloatType = F; |
| 64 + for<'a> Differentiable<&'a Loc<F, N>, Output=Loc<F, N>> { |
85 #[inline] |
| 65 type Output = Loc<F, N>; |
86 fn lipschitz_factor(&self, m : M) -> Option<F> { |
| 66 #[inline] |
87 // f(x)g(x) - f(y)g(y) = f(x)[g(x)-g(y)] - [f(y)-f(x)]g(y) |
| 67 fn differential(&self, x : Loc<F, N>) -> Self::Output { |
88 let &SupportProductFirst(ref f, ref g) = self; |
| 68 self.0.differential(&x) * self.1.apply(&x) + self.1.differential(&x) * self.0.apply(&x) |
89 f.lipschitz_factor(m).map(|l| l * g.bounds().uniform()) |
| 69 } |
90 .zip(g.lipschitz_factor(m).map(|l| l * f.bounds().uniform())) |
| 70 } |
91 .map(|(a, b)| a + b) |
| 71 |
92 } |
| 72 impl<'a, A, B, F : Float, const N : usize> Differentiable<&'a Loc<F, N>> |
93 } |
| 73 for SupportProductFirst<A, B> |
94 |
| 74 where A : Apply<&'a Loc<F, N>, Output=F> |
95 impl<'a, A, B, M : Copy, Domain, F : Float> Lipschitz<M> |
| 75 + Differentiable<&'a Loc<F, N>, Output=Loc<F, N>>, |
96 for Differential<'a, Domain, SupportProductFirst<A, B>> |
| 76 B : Apply<&'a Loc<F, N>, Output=F> |
97 where |
| 77 + Differentiable<&'a Loc<F, N>, Output=Loc<F, N>> { |
98 Domain : Space, |
| 78 type Output = Loc<F, N>; |
99 A : Clone + DifferentiableMapping<Domain> + Lipschitz<M, FloatType = F> + Bounded<F>, |
| 79 #[inline] |
100 B : Clone + DifferentiableMapping<Domain> + Lipschitz<M, FloatType = F> + Bounded<F>, |
| 80 fn differential(&self, x : &'a Loc<F, N>) -> Self::Output { |
101 SupportProductFirst<A, B> : DifferentiableMapping<Domain>, |
| 81 self.0.differential(&x) * self.1.apply(&x) + self.1.differential(&x) * self.0.apply(&x) |
102 for<'b> A::Differential<'b> : Lipschitz<M, FloatType = F> + NormBounded<L2, FloatType=F>, |
| |
103 for<'b> B::Differential<'b> : Lipschitz<M, FloatType = F> + NormBounded<L2, FloatType=F> |
| |
104 { |
| |
105 type FloatType = F; |
| |
106 #[inline] |
| |
107 fn lipschitz_factor(&self, m : M) -> Option<F> { |
| |
108 // ∇[gf] = f∇g + g∇f |
| |
109 // ⟹ ∇[gf](x) - ∇[gf](y) = f(x)∇g(x) + g(x)∇f(x) - f(y)∇g(y) + g(y)∇f(y) |
| |
110 // = f(x)[∇g(x)-∇g(y)] + g(x)∇f(x) - [f(y)-f(x)]∇g(y) + g(y)∇f(y) |
| |
111 // = f(x)[∇g(x)-∇g(y)] + g(x)[∇f(x)-∇f(y)] |
| |
112 // - [f(y)-f(x)]∇g(y) + [g(y)-g(x)]∇f(y) |
| |
113 let &SupportProductFirst(ref f, ref g) = self.base_fn(); |
| |
114 let (df, dg) = (f.diff_ref(), g.diff_ref()); |
| |
115 [ |
| |
116 df.lipschitz_factor(m).map(|l| l * g.bounds().uniform()), |
| |
117 dg.lipschitz_factor(m).map(|l| l * f.bounds().uniform()), |
| |
118 f.lipschitz_factor(m).map(|l| l * dg.norm_bound(L2)), |
| |
119 g.lipschitz_factor(m).map(|l| l * df.norm_bound(L2)) |
| |
120 ].into_iter().sum() |
| 82 } |
121 } |
| 83 } |
122 } |
| 84 |
123 |
| 85 |
124 |
| 86 impl<'a, A, B, F : Float, const N : usize> Support<F, N> |
125 impl<'a, A, B, F : Float, const N : usize> Support<F, N> |
| 87 for SupportProductFirst<A, B> |
126 for SupportProductFirst<A, B> |
| 88 where A : Support<F, N>, |
127 where |
| 89 B : Support<F, N> { |
128 A : Support<F, N>, |
| |
129 B : Support<F, N> |
| |
130 { |
| 90 #[inline] |
131 #[inline] |
| 91 fn support_hint(&self) -> Cube<F, N> { |
132 fn support_hint(&self) -> Cube<F, N> { |
| 92 self.0.support_hint() |
133 self.0.support_hint() |
| 93 } |
134 } |
| 94 |
135 |
| 123 } |
164 } |
| 124 } |
165 } |
| 125 |
166 |
| 126 /// Representation of the sum of two kernels |
167 /// Representation of the sum of two kernels |
| 127 /// |
168 /// |
| 128 /// The kernels typically implement [`Support`] and [`Mapping`][alg_tools::mapping::Mapping]. |
169 /// The kernels typically implement [`Support`] and [`Mapping`]. |
| 129 /// |
170 /// |
| 130 /// The implementation [`Support`] only uses the [`Support::support_hint`] of the first parameter! |
171 /// The implementation [`Support`] only uses the [`Support::support_hint`] of the first parameter! |
| 131 #[derive(Copy,Clone,Serialize,Debug)] |
172 #[derive(Copy,Clone,Serialize,Debug)] |
| 132 pub struct SupportSum<A, B>( |
173 pub struct SupportSum<A, B>( |
| 133 /// First kernel |
174 /// First kernel |
| 134 pub A, |
175 pub A, |
| 135 /// Second kernel |
176 /// Second kernel |
| 136 pub B |
177 pub B |
| 137 ); |
178 ); |
| 138 |
179 |
| 139 impl<'a, A, B, F : Float, const N : usize> Apply<&'a Loc<F, N>> |
180 impl<'a, A, B, F : Float, const N : usize> Mapping<Loc<F, N>> |
| 140 for SupportSum<A, B> |
181 for SupportSum<A, B> |
| 141 where A : Apply<&'a Loc<F, N>, Output=F>, |
182 where |
| 142 B : Apply<&'a Loc<F, N>, Output=F> { |
183 A : Mapping<Loc<F, N>, Codomain = F>, |
| 143 type Output = F; |
184 B : Mapping<Loc<F, N>, Codomain = F>, |
| 144 #[inline] |
185 { |
| 145 fn apply(&self, x : &'a Loc<F, N>) -> Self::Output { |
186 type Codomain = F; |
| 146 self.0.apply(x) + self.1.apply(x) |
187 |
| 147 } |
188 #[inline] |
| 148 } |
189 fn apply<I : Instance<Loc<F, N>>>(&self, x : I) -> Self::Codomain { |
| 149 |
190 self.0.apply(x.ref_instance()) + self.1.apply(x) |
| 150 impl<A, B, F : Float, const N : usize> Apply<Loc<F, N>> |
191 } |
| |
192 } |
| |
193 |
| |
194 impl<'a, A, B, F : Float, const N : usize> DifferentiableImpl<Loc<F, N>> |
| 151 for SupportSum<A, B> |
195 for SupportSum<A, B> |
| 152 where A : for<'a> Apply<&'a Loc<F, N>, Output=F>, |
196 where |
| 153 B : for<'a> Apply<&'a Loc<F, N>, Output=F> { |
197 A : DifferentiableMapping< |
| 154 type Output = F; |
198 Loc<F, N>, |
| 155 #[inline] |
199 DerivativeDomain = Loc<F, N> |
| 156 fn apply(&self, x : Loc<F, N>) -> Self::Output { |
200 >, |
| 157 self.0.apply(&x) + self.1.apply(&x) |
201 B : DifferentiableMapping< |
| 158 } |
202 Loc<F, N>, |
| 159 } |
203 DerivativeDomain = Loc<F, N>, |
| 160 |
204 > |
| 161 impl<'a, A, B, F : Float, const N : usize> Differentiable<&'a Loc<F, N>> |
205 { |
| 162 for SupportSum<A, B> |
206 |
| 163 where A : Differentiable<&'a Loc<F, N>, Output=Loc<F, N>>, |
207 type Derivative = Loc<F, N>; |
| 164 B : Differentiable<&'a Loc<F, N>, Output=Loc<F, N>> { |
208 |
| 165 type Output = Loc<F, N>; |
209 #[inline] |
| 166 #[inline] |
210 fn differential_impl<I : Instance<Loc<F, N>>>(&self, x : I) -> Self::Derivative { |
| 167 fn differential(&self, x : &'a Loc<F, N>) -> Self::Output { |
211 self.0.differential(x.ref_instance()) + self.1.differential(x) |
| 168 self.0.differential(x) + self.1.differential(x) |
212 } |
| 169 } |
213 } |
| 170 } |
214 |
| 171 |
|
| 172 impl<A, B, F : Float, const N : usize> Differentiable<Loc<F, N>> |
|
| 173 for SupportSum<A, B> |
|
| 174 where A : for<'a> Differentiable<&'a Loc<F, N>, Output=Loc<F, N>>, |
|
| 175 B : for<'a> Differentiable<&'a Loc<F, N>, Output=Loc<F, N>> { |
|
| 176 type Output = Loc<F, N>; |
|
| 177 #[inline] |
|
| 178 fn differential(&self, x : Loc<F, N>) -> Self::Output { |
|
| 179 self.0.differential(&x) + self.1.differential(&x) |
|
| 180 } |
|
| 181 } |
|
| 182 |
215 |
| 183 impl<'a, A, B, F : Float, const N : usize> Support<F, N> |
216 impl<'a, A, B, F : Float, const N : usize> Support<F, N> |
| 184 for SupportSum<A, B> |
217 for SupportSum<A, B> |
| 185 where A : Support<F, N>, |
218 where A : Support<F, N>, |
| 186 B : Support<F, N>, |
219 B : Support<F, N>, |
| 187 Cube<F, N> : SetOrd { |
220 Cube<F, N> : SetOrd { |
| |
221 |
| 188 #[inline] |
222 #[inline] |
| 189 fn support_hint(&self) -> Cube<F, N> { |
223 fn support_hint(&self) -> Cube<F, N> { |
| 190 self.0.support_hint().common(&self.1.support_hint()) |
224 self.0.support_hint().common(&self.1.support_hint()) |
| 191 } |
225 } |
| 192 |
226 |
| 250 /// Second kernel |
303 /// Second kernel |
| 251 pub B |
304 pub B |
| 252 ); |
305 ); |
| 253 |
306 |
| 254 impl<F : Float, M, A, B> Lipschitz<M> for Convolution<A, B> |
307 impl<F : Float, M, A, B> Lipschitz<M> for Convolution<A, B> |
| 255 where A : Bounded<F> , |
308 where A : Norm<F, L1> , |
| 256 B : Lipschitz<M, FloatType = F> { |
309 B : Lipschitz<M, FloatType = F> { |
| 257 type FloatType = F; |
310 type FloatType = F; |
| 258 |
311 |
| 259 fn lipschitz_factor(&self, m : M) -> Option<F> { |
312 fn lipschitz_factor(&self, m : M) -> Option<F> { |
| 260 self.1.lipschitz_factor(m).map(|l| l * self.0.bounds().uniform()) |
313 // For [f * g](x) = ∫ f(x-y)g(y) dy we have |
| |
314 // [f * g](x) - [f * g](z) = ∫ [f(x-y)-f(z-y)]g(y) dy. |
| |
315 // Hence |[f * g](x) - [f * g](z)| ≤ ∫ |f(x-y)-f(z-y)|g(y)| dy. |
| |
316 // ≤ L|x-z| ∫ |g(y)| dy, |
| |
317 // where L is the Lipschitz factor of f. |
| |
318 self.1.lipschitz_factor(m).map(|l| l * self.0.norm(L1)) |
| |
319 } |
| |
320 } |
| |
321 |
| |
322 impl<'b, F : Float, M, A, B, Domain> Lipschitz<M> |
| |
323 for Differential<'b, Domain, Convolution<A, B>> |
| |
324 where |
| |
325 Domain : Space, |
| |
326 A : Clone + Norm<F, L1> , |
| |
327 Convolution<A, B> : DifferentiableMapping<Domain, Codomain=F>, |
| |
328 B : Clone + DifferentiableMapping<Domain, Codomain=F>, |
| |
329 for<'a> B :: Differential<'a> : Lipschitz<M, FloatType = F> |
| |
330 { |
| |
331 type FloatType = F; |
| |
332 |
| |
333 fn lipschitz_factor(&self, m : M) -> Option<F> { |
| |
334 // For [f * g](x) = ∫ f(x-y)g(y) dy we have |
| |
335 // ∇[f * g](x) - ∇[f * g](z) = ∫ [∇f(x-y)-∇f(z-y)]g(y) dy. |
| |
336 // Hence |∇[f * g](x) - ∇[f * g](z)| ≤ ∫ |∇f(x-y)-∇f(z-y)|g(y)| dy. |
| |
337 // ≤ L|x-z| ∫ |g(y)| dy, |
| |
338 // where L is the Lipschitz factor of ∇f. |
| |
339 let base = self.base_fn(); |
| |
340 base.1.diff_ref().lipschitz_factor(m).map(|l| l * base.0.norm(L1)) |
| 261 } |
341 } |
| 262 } |
342 } |
| 263 |
343 |
| 264 /// Representation of the autoconvolution of a kernel. |
344 /// Representation of the autoconvolution of a kernel. |
| 265 /// |
345 /// |
| 266 /// The kernel typically implements [`Support`] and [`Mapping`][alg_tools::mapping::Mapping]. |
346 /// The kernel typically implements [`Support`] and [`Mapping`]. |
| 267 /// |
347 /// |
| 268 /// Trait implementations have to be on a case-by-case basis. |
348 /// Trait implementations have to be on a case-by-case basis. |
| 269 #[derive(Copy,Clone,Serialize,Debug,Eq,PartialEq)] |
349 #[derive(Copy,Clone,Serialize,Debug,Eq,PartialEq)] |
| 270 pub struct AutoConvolution<A>( |
350 pub struct AutoConvolution<A>( |
| 271 /// The kernel to be autoconvolved |
351 /// The kernel to be autoconvolved |
| 272 pub A |
352 pub A |
| 273 ); |
353 ); |
| 274 |
354 |
| 275 impl<F : Float, M, C> Lipschitz<M> for AutoConvolution<C> |
355 impl<F : Float, M, C> Lipschitz<M> for AutoConvolution<C> |
| 276 where C : Lipschitz<M, FloatType = F> + Bounded<F> { |
356 where C : Lipschitz<M, FloatType = F> + Norm<F, L1> { |
| 277 type FloatType = F; |
357 type FloatType = F; |
| 278 |
358 |
| 279 fn lipschitz_factor(&self, m : M) -> Option<F> { |
359 fn lipschitz_factor(&self, m : M) -> Option<F> { |
| 280 self.0.lipschitz_factor(m).map(|l| l * self.0.bounds().uniform()) |
360 self.0.lipschitz_factor(m).map(|l| l * self.0.norm(L1)) |
| |
361 } |
| |
362 } |
| |
363 |
| |
364 impl<'b, F : Float, M, C, Domain> Lipschitz<M> |
| |
365 for Differential<'b, Domain, AutoConvolution<C>> |
| |
366 where |
| |
367 Domain : Space, |
| |
368 C : Clone + Norm<F, L1> + DifferentiableMapping<Domain, Codomain=F>, |
| |
369 AutoConvolution<C> : DifferentiableMapping<Domain, Codomain=F>, |
| |
370 for<'a> C :: Differential<'a> : Lipschitz<M, FloatType = F> |
| |
371 { |
| |
372 type FloatType = F; |
| |
373 |
| |
374 fn lipschitz_factor(&self, m : M) -> Option<F> { |
| |
375 let base = self.base_fn(); |
| |
376 base.0.diff_ref().lipschitz_factor(m).map(|l| l * base.0.norm(L1)) |
| 281 } |
377 } |
| 282 } |
378 } |
| 283 |
379 |
| 284 |
380 |
| 285 /// Representation a multi-dimensional product of a one-dimensional kernel. |
381 /// Representation a multi-dimensional product of a one-dimensional kernel. |
| 286 /// |
382 /// |
| 287 /// For $G: ℝ → ℝ$, this is the function $F(x\_1, …, x\_n) := \prod_{i=1}^n G(x\_i)$. |
383 /// For $G: ℝ → ℝ$, this is the function $F(x\_1, …, x\_n) := \prod_{i=1}^n G(x\_i)$. |
| 288 /// The kernel $G$ typically implements [`Support`] and [`Mapping`][alg_tools::mapping::Mapping] |
384 /// The kernel $G$ typically implements [`Support`] and [`Mapping`] |
| 289 /// on [`Loc<F, 1>`]. Then the product implements them on [`Loc<F, N>`]. |
385 /// on [`Loc<F, 1>`]. Then the product implements them on [`Loc<F, N>`]. |
| 290 #[derive(Copy,Clone,Serialize,Debug,Eq,PartialEq)] |
386 #[derive(Copy,Clone,Serialize,Debug,Eq,PartialEq)] |
| |
387 #[allow(dead_code)] |
| 291 struct UniformProduct<G, const N : usize>( |
388 struct UniformProduct<G, const N : usize>( |
| 292 /// The one-dimensional kernel |
389 /// The one-dimensional kernel |
| 293 G |
390 G |
| 294 ); |
391 ); |
| 295 |
392 |
| 296 impl<'a, G, F : Float, const N : usize> Apply<&'a Loc<F, N>> |
393 impl<'a, G, F : Float, const N : usize> Mapping<Loc<F, N>> |
| 297 for UniformProduct<G, N> |
394 for UniformProduct<G, N> |
| 298 where G : Apply<Loc<F, 1>, Output=F> { |
395 where |
| 299 type Output = F; |
396 G : Mapping<Loc<F, 1>, Codomain = F> |
| 300 #[inline] |
397 { |
| 301 fn apply(&self, x : &'a Loc<F, N>) -> F { |
398 type Codomain = F; |
| 302 x.iter().map(|&y| self.0.apply(Loc([y]))).product() |
399 |
| 303 } |
400 #[inline] |
| 304 } |
401 fn apply<I : Instance<Loc<F, N>>>(&self, x : I) -> F { |
| 305 |
402 x.cow().iter().map(|&y| self.0.apply(Loc([y]))).product() |
| 306 impl<G, F : Float, const N : usize> Apply<Loc<F, N>> |
403 } |
| |
404 } |
| |
405 |
| |
406 |
| |
407 |
| |
408 impl<'a, G, F : Float, const N : usize> DifferentiableImpl<Loc<F, N>> |
| 307 for UniformProduct<G, N> |
409 for UniformProduct<G, N> |
| 308 where G : Apply<Loc<F, 1>, Output=F> { |
410 where |
| 309 type Output = F; |
411 G : DifferentiableMapping< |
| 310 #[inline] |
412 Loc<F, 1>, |
| 311 fn apply(&self, x : Loc<F, N>) -> F { |
413 DerivativeDomain = F, |
| 312 x.into_iter().map(|y| self.0.apply(Loc([y]))).product() |
414 Codomain = F, |
| 313 } |
415 > |
| 314 } |
416 { |
| 315 |
417 type Derivative = Loc<F, N>; |
| 316 impl<'a, G, F : Float, const N : usize> Differentiable<&'a Loc<F, N>> |
418 |
| 317 for UniformProduct<G, N> |
419 #[inline] |
| 318 where G : Apply<Loc<F, 1>, Output=F> + Differentiable<Loc<F, 1>, Output=F> { |
420 fn differential_impl<I : Instance<Loc<F, N>>>(&self, x0 : I) -> Loc<F, N> { |
| 319 type Output = Loc<F, N>; |
421 x0.eval(|x| { |
| 320 #[inline] |
422 let vs = x.map(|y| self.0.apply(Loc([y]))); |
| 321 fn differential(&self, x : &'a Loc<F, N>) -> Loc<F, N> { |
423 product_differential(x, &vs, |y| self.0.differential(Loc([y]))) |
| 322 let vs = x.map(|y| self.0.apply(Loc([y]))); |
424 }) |
| 323 product_differential(x, &vs, |y| self.0.differential(Loc([y]))) |
|
| 324 } |
425 } |
| 325 } |
426 } |
| 326 |
427 |
| 327 /// Helper function to calulate the differential of $f(x)=∏_{i=1}^N g(x_i)$. |
428 /// Helper function to calulate the differential of $f(x)=∏_{i=1}^N g(x_i)$. |
| 328 /// |
429 /// |
| 340 .filter_map(|(v, j)| (j != i).then_some(*v)) |
441 .filter_map(|(v, j)| (j != i).then_some(*v)) |
| 341 .product() |
442 .product() |
| 342 }).into() |
443 }).into() |
| 343 } |
444 } |
| 344 |
445 |
| 345 impl<G, F : Float, const N : usize> Differentiable<Loc<F, N>> |
446 /// Helper function to calulate the Lipschitz factor of $∇f$ for $f(x)=∏_{i=1}^N g(x_i)$. |
| 346 for UniformProduct<G, N> |
447 /// |
| 347 where G : Apply<Loc<F, 1>, Output=F> + Differentiable<Loc<F, 1>, Output=F> { |
448 /// The parameter `bound` is a bound on $|g|_∞$, `lip` is a Lipschitz factor for $g$, |
| 348 type Output = Loc<F, N>; |
449 /// `dbound` is a bound on $|∇g|_∞$, and `dlip` a Lipschitz factor for $∇g$. |
| 349 #[inline] |
450 #[inline] |
| 350 fn differential(&self, x : Loc<F, N>) -> Loc<F, N> { |
451 pub(crate) fn product_differential_lipschitz_factor<F : Float, const N : usize>( |
| 351 self.differential(&x) |
452 bound : F, |
| |
453 lip : F, |
| |
454 dbound : F, |
| |
455 dlip : F |
| |
456 ) -> F { |
| |
457 // For arbitrary ψ(x) = ∏_{i=1}^n ψ_i(x_i), we have |
| |
458 // ψ(x) - ψ(y) = ∑_i [ψ_i(x_i)-ψ_i(y_i)] ∏_{j ≠ i} ψ_j(x_j) |
| |
459 // by a simple recursive argument. In particular, if ψ_i=g for all i, j, we have |
| |
460 // |ψ(x) - ψ(y)| ≤ ∑_i L_g M_g^{n-1}|x-y|, where L_g is the Lipschitz factor of g, and |
| |
461 // M_g a bound on it. |
| |
462 // |
| |
463 // We also have in the general case ∇ψ(x) = ∑_i ∇ψ_i(x_i) ∏_{j ≠ i} ψ_j(x_j), whence |
| |
464 // using the previous formula for each i with f_i=∇ψ_i and f_j=ψ_j for j ≠ i, we get |
| |
465 // ∇ψ(x) - ∇ψ(y) = ∑_i[ ∇ψ_i(x_i)∏_{j ≠ i} ψ_j(x_j) - ∇ψ_i(y_i)∏_{j ≠ i} ψ_j(y_j)] |
| |
466 // = ∑_i[ [∇ψ_i(x_i) - ∇ψ_j(x_j)] ∏_{j ≠ i}ψ_j(x_j) |
| |
467 // + [∑_{k ≠ i} [ψ_k(x_k) - ∇ψ_k(x_k)] ∏_{j ≠ i, k}ψ_j(x_j)]∇ψ_i(x_i)]. |
| |
468 // With $ψ_i=g for all i, j, it follows that |
| |
469 // |∇ψ(x) - ∇ψ(y)| ≤ ∑_i L_{∇g} M_g^{n-1} + ∑_{k ≠ i} L_g M_g^{n-2} M_{∇g} |
| |
470 // = n [L_{∇g} M_g^{n-1} + (n-1) L_g M_g^{n-2} M_{∇g}]. |
| |
471 // = n M_g^{n-2}[L_{∇g} M_g + (n-1) L_g M_{∇g}]. |
| |
472 if N >= 2 { |
| |
473 F::cast_from(N) * bound.powi((N-2) as i32) |
| |
474 * (dlip * bound + F::cast_from(N-1) * lip * dbound) |
| |
475 } else if N==1 { |
| |
476 dlip |
| |
477 } else { |
| |
478 panic!("Invalid dimension") |
| 352 } |
479 } |
| 353 } |
480 } |
| 354 |
481 |
| 355 impl<G, F : Float, const N : usize> Support<F, N> |
482 impl<G, F : Float, const N : usize> Support<F, N> |
| 356 for UniformProduct<G, N> |
483 for UniformProduct<G, N> |