12 Bounds, |
12 Bounds, |
13 LocalAnalysis, |
13 LocalAnalysis, |
14 GlobalAnalysis, |
14 GlobalAnalysis, |
15 Bounded, |
15 Bounded, |
16 }; |
16 }; |
17 use alg_tools::mapping::Apply; |
17 use alg_tools::mapping::{Apply, Differentiable}; |
18 use alg_tools::maputil::{array_init, map2}; |
18 use alg_tools::maputil::{array_init, map2, map1_indexed}; |
19 use alg_tools::sets::SetOrd; |
19 use alg_tools::sets::SetOrd; |
20 |
20 |
21 use crate::fourier::Fourier; |
21 use crate::fourier::Fourier; |
|
22 use crate::types::Lipschitz; |
22 |
23 |
23 /// Representation of the product of two kernels. |
24 /// Representation of the product of two kernels. |
24 /// |
25 /// |
25 /// The kernels typically implement [`Support`] and [`Mapping`][alg_tools::mapping::Mapping]. |
26 /// The kernels typically implement [`Support`] and [`Mapping`][alg_tools::mapping::Mapping]. |
26 /// |
27 /// |
53 fn apply(&self, x : &'a Loc<F, N>) -> Self::Output { |
54 fn apply(&self, x : &'a Loc<F, N>) -> Self::Output { |
54 self.0.apply(x) * self.1.apply(x) |
55 self.0.apply(x) * self.1.apply(x) |
55 } |
56 } |
56 } |
57 } |
57 |
58 |
|
59 impl<A, B, F : Float, const N : usize> Differentiable<Loc<F, N>> |
|
60 for SupportProductFirst<A, B> |
|
61 where A : for<'a> Apply<&'a Loc<F, N>, Output=F> |
|
62 + for<'a> Differentiable<&'a Loc<F, N>, Output=Loc<F, N>>, |
|
63 B : for<'a> Apply<&'a Loc<F, N>, Output=F> |
|
64 + for<'a> Differentiable<&'a Loc<F, N>, Output=Loc<F, N>> { |
|
65 type Output = Loc<F, N>; |
|
66 #[inline] |
|
67 fn differential(&self, x : Loc<F, N>) -> Self::Output { |
|
68 self.0.differential(&x) * self.1.apply(&x) + self.1.differential(&x) * self.0.apply(&x) |
|
69 } |
|
70 } |
|
71 |
|
72 impl<'a, A, B, F : Float, const N : usize> Differentiable<&'a Loc<F, N>> |
|
73 for SupportProductFirst<A, B> |
|
74 where A : Apply<&'a Loc<F, N>, Output=F> |
|
75 + Differentiable<&'a Loc<F, N>, Output=Loc<F, N>>, |
|
76 B : Apply<&'a Loc<F, N>, Output=F> |
|
77 + Differentiable<&'a Loc<F, N>, Output=Loc<F, N>> { |
|
78 type Output = Loc<F, N>; |
|
79 #[inline] |
|
80 fn differential(&self, x : &'a Loc<F, N>) -> Self::Output { |
|
81 self.0.differential(&x) * self.1.apply(&x) + self.1.differential(&x) * self.0.apply(&x) |
|
82 } |
|
83 } |
|
84 |
|
85 |
58 impl<'a, A, B, F : Float, const N : usize> Support<F, N> |
86 impl<'a, A, B, F : Float, const N : usize> Support<F, N> |
59 for SupportProductFirst<A, B> |
87 for SupportProductFirst<A, B> |
60 where A : Support<F, N>, |
88 where A : Support<F, N>, |
61 B : Support<F, N> { |
89 B : Support<F, N> { |
62 #[inline] |
90 #[inline] |
128 fn apply(&self, x : Loc<F, N>) -> Self::Output { |
156 fn apply(&self, x : Loc<F, N>) -> Self::Output { |
129 self.0.apply(&x) + self.1.apply(&x) |
157 self.0.apply(&x) + self.1.apply(&x) |
130 } |
158 } |
131 } |
159 } |
132 |
160 |
|
161 impl<'a, A, B, F : Float, const N : usize> Differentiable<&'a Loc<F, N>> |
|
162 for SupportSum<A, B> |
|
163 where A : Differentiable<&'a Loc<F, N>, Output=Loc<F, N>>, |
|
164 B : Differentiable<&'a Loc<F, N>, Output=Loc<F, N>> { |
|
165 type Output = Loc<F, N>; |
|
166 #[inline] |
|
167 fn differential(&self, x : &'a Loc<F, N>) -> Self::Output { |
|
168 self.0.differential(x) + self.1.differential(x) |
|
169 } |
|
170 } |
|
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 |
133 impl<'a, A, B, F : Float, const N : usize> Support<F, N> |
183 impl<'a, A, B, F : Float, const N : usize> Support<F, N> |
134 for SupportSum<A, B> |
184 for SupportSum<A, B> |
135 where A : Support<F, N>, |
185 where A : Support<F, N>, |
136 B : Support<F, N>, |
186 B : Support<F, N>, |
137 Cube<F, N> : SetOrd { |
187 Cube<F, N> : SetOrd { |
171 #[inline] |
221 #[inline] |
172 fn local_analysis(&self, cube : &Cube<F, N>) -> Bounds<F> { |
222 fn local_analysis(&self, cube : &Cube<F, N>) -> Bounds<F> { |
173 self.0.local_analysis(cube) + self.1.local_analysis(cube) |
223 self.0.local_analysis(cube) + self.1.local_analysis(cube) |
174 } |
224 } |
175 } |
225 } |
|
226 |
|
227 impl<F : Float, M : Copy, A, B> Lipschitz<M> for SupportSum<A, B> |
|
228 where A : Lipschitz<M, FloatType = F>, |
|
229 B : Lipschitz<M, FloatType = F> { |
|
230 type FloatType = F; |
|
231 |
|
232 fn lipschitz_factor(&self, m : M) -> Option<F> { |
|
233 match (self.0.lipschitz_factor(m), self.1.lipschitz_factor(m)) { |
|
234 (Some(l0), Some(l1)) => Some(l0 + l1), |
|
235 _ => None |
|
236 } |
|
237 } |
|
238 } |
|
239 |
176 |
240 |
177 /// Representation of the convolution of two kernels. |
241 /// Representation of the convolution of two kernels. |
178 /// |
242 /// |
179 /// The kernels typically implement [`Support`]s and [`Mapping`][alg_tools::mapping::Mapping]. |
243 /// The kernels typically implement [`Support`]s and [`Mapping`][alg_tools::mapping::Mapping]. |
180 // |
244 // |
185 pub A, |
249 pub A, |
186 /// Second kernel |
250 /// Second kernel |
187 pub B |
251 pub B |
188 ); |
252 ); |
189 |
253 |
|
254 impl<F : Float, M, A, B> Lipschitz<M> for Convolution<A, B> |
|
255 where A : Bounded<F> , |
|
256 B : Lipschitz<M, FloatType = F> { |
|
257 type FloatType = F; |
|
258 |
|
259 fn lipschitz_factor(&self, m : M) -> Option<F> { |
|
260 self.1.lipschitz_factor(m).map(|l| l * self.0.bounds().uniform()) |
|
261 } |
|
262 } |
|
263 |
190 /// Representation of the autoconvolution of a kernel. |
264 /// Representation of the autoconvolution of a kernel. |
191 /// |
265 /// |
192 /// The kernel typically implements [`Support`] and [`Mapping`][alg_tools::mapping::Mapping]. |
266 /// The kernel typically implements [`Support`] and [`Mapping`][alg_tools::mapping::Mapping]. |
193 /// |
267 /// |
194 /// Trait implementations have to be on a case-by-case basis. |
268 /// Trait implementations have to be on a case-by-case basis. |
195 #[derive(Copy,Clone,Serialize,Debug,Eq,PartialEq)] |
269 #[derive(Copy,Clone,Serialize,Debug,Eq,PartialEq)] |
196 pub struct AutoConvolution<A>( |
270 pub struct AutoConvolution<A>( |
197 /// The kernel to be autoconvolved |
271 /// The kernel to be autoconvolved |
198 pub A |
272 pub A |
199 ); |
273 ); |
|
274 |
|
275 impl<F : Float, M, C> Lipschitz<M> for AutoConvolution<C> |
|
276 where C : Lipschitz<M, FloatType = F> + Bounded<F> { |
|
277 type FloatType = F; |
|
278 |
|
279 fn lipschitz_factor(&self, m : M) -> Option<F> { |
|
280 self.0.lipschitz_factor(m).map(|l| l * self.0.bounds().uniform()) |
|
281 } |
|
282 } |
|
283 |
200 |
284 |
201 /// Representation a multi-dimensional product of a one-dimensional kernel. |
285 /// Representation a multi-dimensional product of a one-dimensional kernel. |
202 /// |
286 /// |
203 /// For $G: ℝ → ℝ$, this is the function $F(x\_1, …, x\_n) := \prod_{i=1}^n G(x\_i)$. |
287 /// For $G: ℝ → ℝ$, this is the function $F(x\_1, …, x\_n) := \prod_{i=1}^n G(x\_i)$. |
204 /// The kernel $G$ typically implements [`Support`] and [`Mapping`][alg_tools::mapping::Mapping] |
288 /// The kernel $G$ typically implements [`Support`] and [`Mapping`][alg_tools::mapping::Mapping] |
224 where G : Apply<Loc<F, 1>, Output=F> { |
308 where G : Apply<Loc<F, 1>, Output=F> { |
225 type Output = F; |
309 type Output = F; |
226 #[inline] |
310 #[inline] |
227 fn apply(&self, x : Loc<F, N>) -> F { |
311 fn apply(&self, x : Loc<F, N>) -> F { |
228 x.into_iter().map(|y| self.0.apply(Loc([y]))).product() |
312 x.into_iter().map(|y| self.0.apply(Loc([y]))).product() |
|
313 } |
|
314 } |
|
315 |
|
316 impl<'a, G, F : Float, const N : usize> Differentiable<&'a Loc<F, N>> |
|
317 for UniformProduct<G, N> |
|
318 where G : Apply<Loc<F, 1>, Output=F> + Differentiable<Loc<F, 1>, Output=F> { |
|
319 type Output = Loc<F, N>; |
|
320 #[inline] |
|
321 fn differential(&self, x : &'a Loc<F, N>) -> Loc<F, N> { |
|
322 let vs = x.map(|y| self.0.apply(Loc([y]))); |
|
323 product_differential(x, &vs, |y| self.0.differential(Loc([y]))) |
|
324 } |
|
325 } |
|
326 |
|
327 /// Helper function to calulate the differential of $f(x)=∏_{i=1}^N g(x_i)$. |
|
328 /// |
|
329 /// The vector `x` is the location, `vs` consists of the values `g(x_i)`, and |
|
330 /// `gd` calculates the derivative `g'`. |
|
331 #[inline] |
|
332 pub(crate) fn product_differential<F : Float, G : Fn(F) -> F, const N : usize>( |
|
333 x : &Loc<F, N>, |
|
334 vs : &Loc<F, N>, |
|
335 gd : G |
|
336 ) -> Loc<F, N> { |
|
337 map1_indexed(x, |i, &y| { |
|
338 gd(y) * vs.iter() |
|
339 .zip(0..) |
|
340 .filter_map(|(v, j)| (j != i).then_some(*v)) |
|
341 .product() |
|
342 }).into() |
|
343 } |
|
344 |
|
345 impl<G, F : Float, const N : usize> Differentiable<Loc<F, N>> |
|
346 for UniformProduct<G, N> |
|
347 where G : Apply<Loc<F, 1>, Output=F> + Differentiable<Loc<F, 1>, Output=F> { |
|
348 type Output = Loc<F, N>; |
|
349 #[inline] |
|
350 fn differential(&self, x : Loc<F, N>) -> Loc<F, N> { |
|
351 self.differential(&x) |
229 } |
352 } |
230 } |
353 } |
231 |
354 |
232 impl<G, F : Float, const N : usize> Support<F, N> |
355 impl<G, F : Float, const N : usize> Support<F, N> |
233 for UniformProduct<G, N> |
356 for UniformProduct<G, N> |