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> |