37 /// -2 y^3-2 y^2+\frac{1}{3} & -\frac{1}{2}<y\leq 0, \\\\ |
42 /// -2 y^3-2 y^2+\frac{1}{3} & -\frac{1}{2}<y\leq 0, \\\\ |
38 /// 2 y^3-2 y^2+\frac{1}{3} & 0<y<\frac{1}{2}, \\\\ |
43 /// 2 y^3-2 y^2+\frac{1}{3} & 0<y<\frac{1}{2}, \\\\ |
39 /// -\frac{2}{3} (y-1)^3 & \frac{1}{2}\leq y<1. \\\\ |
44 /// -\frac{2}{3} (y-1)^3 & \frac{1}{2}\leq y<1. \\\\ |
40 /// \end{cases} |
45 /// \end{cases} |
41 /// $$ |
46 /// $$ |
|
47 // Hence |
|
48 // $$ |
|
49 // (h\*h)'(y) = |
|
50 // \begin{cases} |
|
51 // 2 (y+1)^2 & -1<y\leq -\frac{1}{2}, \\\\ |
|
52 // -6 y^2-4 y & -\frac{1}{2}<y\leq 0, \\\\ |
|
53 // 6 y^2-4 y & 0<y<\frac{1}{2}, \\\\ |
|
54 // -2 (y-1)^2 & \frac{1}{2}\leq y<1. \\\\ |
|
55 // \end{cases} |
|
56 // $$ |
|
57 // as well as |
|
58 // $$ |
|
59 // (h\*h)''(y) = |
|
60 // \begin{cases} |
|
61 // 4 (y+1) & -1<y\leq -\frac{1}{2}, \\\\ |
|
62 // -12 y-4 & -\frac{1}{2}<y\leq 0, \\\\ |
|
63 // 12 y-4 & 0<y<\frac{1}{2}, \\\\ |
|
64 // -4 (y-1) & \frac{1}{2}\leq y<1. \\\\ |
|
65 // \end{cases} |
|
66 // $$ |
|
67 // This is maximised at y=±1/2 with value 2, and minimised at y=0 with value -4. |
|
68 // Now observe that |
|
69 // $$ |
|
70 // [∇f(x\_1, …, x\_n)]_j = \frac{4}{σ} (h\*h)'(x\_j/σ) \prod\_{j ≠ i} \frac{4}{σ} (h\*h)(x\_i/σ) |
|
71 // $$ |
42 #[derive(Copy,Clone,Debug,Serialize,Eq)] |
72 #[derive(Copy,Clone,Debug,Serialize,Eq)] |
43 pub struct HatConv<S : Constant, const N : usize> { |
73 pub struct HatConv<S : Constant, const N : usize> { |
44 /// The parameter $σ$ of the kernel. |
74 /// The parameter $σ$ of the kernel. |
45 pub radius : S, |
75 pub radius : S, |
46 } |
76 } |
59 pub fn radius(&self) -> S::Type { |
89 pub fn radius(&self) -> S::Type { |
60 self.radius.value() |
90 self.radius.value() |
61 } |
91 } |
62 } |
92 } |
63 |
93 |
64 impl<'a, S, const N : usize> Apply<&'a Loc<S::Type, N>> for HatConv<S, N> |
94 impl<'a, S, const N : usize> Mapping<Loc<S::Type, N>> for HatConv<S, N> |
65 where S : Constant { |
95 where S : Constant { |
66 type Output = S::Type; |
96 type Codomain = S::Type; |
67 #[inline] |
97 |
68 fn apply(&self, y : &'a Loc<S::Type, N>) -> Self::Output { |
98 #[inline] |
|
99 fn apply<I : Instance<Loc<S::Type, N>>>(&self, y : I) -> Self::Codomain { |
69 let σ = self.radius(); |
100 let σ = self.radius(); |
70 y.product_map(|x| { |
101 y.cow().product_map(|x| { |
71 self.value_1d_σ1(x / σ) / σ |
102 self.value_1d_σ1(x / σ) / σ |
72 }) |
103 }) |
73 } |
|
74 } |
|
75 |
|
76 impl<'a, S, const N : usize> Apply<Loc<S::Type, N>> for HatConv<S, N> |
|
77 where S : Constant { |
|
78 type Output = S::Type; |
|
79 #[inline] |
|
80 fn apply(&self, y : Loc<S::Type, N>) -> Self::Output { |
|
81 self.apply(&y) |
|
82 } |
104 } |
83 } |
105 } |
84 |
106 |
85 #[replace_float_literals(S::Type::cast_from(literal))] |
107 #[replace_float_literals(S::Type::cast_from(literal))] |
86 impl<S, const N : usize> Lipschitz<L1> for HatConv<S, N> |
108 impl<S, const N : usize> Lipschitz<L1> for HatConv<S, N> |
93 // = [ψ_1(x_1)-ψ_1(y_1)] ∏_{i=2}^N ψ_i(x_i) |
115 // = [ψ_1(x_1)-ψ_1(y_1)] ∏_{i=2}^N ψ_i(x_i) |
94 // + ψ_1(y_1)[ ∏_{i=2}^N ψ_i(x_i) - ∏_{i=2}^N ψ_i(y_i)] |
116 // + ψ_1(y_1)[ ∏_{i=2}^N ψ_i(x_i) - ∏_{i=2}^N ψ_i(y_i)] |
95 // = ∑_{j=1}^N [ψ_j(x_j)-ψ_j(y_j)]∏_{i > j} ψ_i(x_i) ∏_{i < j} ψ_i(y_i) |
117 // = ∑_{j=1}^N [ψ_j(x_j)-ψ_j(y_j)]∏_{i > j} ψ_i(x_i) ∏_{i < j} ψ_i(y_i) |
96 // Thus |
118 // Thus |
97 // |∏_{i=1}^N ψ_i(x_i) - ∏_{i=1}^N ψ_i(y_i)| |
119 // |∏_{i=1}^N ψ_i(x_i) - ∏_{i=1}^N ψ_i(y_i)| |
98 // ≤ ∑_{j=1}^N |ψ_j(x_j)-ψ_j(y_j)| ∏_{j ≠ i} \max_i |ψ_i| |
120 // ≤ ∑_{j=1}^N |ψ_j(x_j)-ψ_j(y_j)| ∏_{j ≠ i} \max_j |ψ_j| |
99 let σ = self.radius(); |
121 let σ = self.radius(); |
100 let l1d = self.lipschitz_1d_σ1() / (σ*σ); |
122 let l1d = self.lipschitz_1d_σ1() / (σ*σ); |
101 let m1d = self.value_1d_σ1(0.0) / σ; |
123 let m1d = self.value_1d_σ1(0.0) / σ; |
102 Some(l1d * m1d.powi(N as i32 - 1)) |
124 Some(l1d * m1d.powi(N as i32 - 1)) |
103 } |
125 } |
111 self.lipschitz_factor(L1).map(|l1| l1 * <S::Type>::cast_from(N).sqrt()) |
133 self.lipschitz_factor(L1).map(|l1| l1 * <S::Type>::cast_from(N).sqrt()) |
112 } |
134 } |
113 } |
135 } |
114 |
136 |
115 |
137 |
116 impl<'a, S, const N : usize> Differentiable<&'a Loc<S::Type, N>> for HatConv<S, N> |
138 impl<'a, S, const N : usize> DifferentiableImpl<Loc<S::Type, N>> for HatConv<S, N> |
117 where S : Constant { |
139 where S : Constant { |
118 type Output = Loc<S::Type, N>; |
140 type Derivative = Loc<S::Type, N>; |
119 #[inline] |
141 |
120 fn differential(&self, y : &'a Loc<S::Type, N>) -> Self::Output { |
142 #[inline] |
|
143 fn differential_impl<I : Instance<Loc<S::Type, N>>>(&self, y0 : I) -> Self::Derivative { |
|
144 let y = y0.cow(); |
121 let σ = self.radius(); |
145 let σ = self.radius(); |
122 let σ2 = σ * σ; |
146 let σ2 = σ * σ; |
123 let vs = y.map(|x| { |
147 let vs = y.map(|x| { |
124 self.value_1d_σ1(x / σ) / σ |
148 self.value_1d_σ1(x / σ) / σ |
125 }); |
149 }); |
126 product_differential(y, &vs, |x| { |
150 product_differential(&*y, &vs, |x| { |
127 self.diff_1d_σ1(x / σ) / σ2 |
151 self.diff_1d_σ1(x / σ) / σ2 |
128 }) |
152 }) |
129 } |
153 } |
130 } |
154 } |
131 |
155 |
132 impl<'a, S, const N : usize> Differentiable<Loc<S::Type, N>> for HatConv<S, N> |
156 |
133 where S : Constant { |
157 #[replace_float_literals(S::Type::cast_from(literal))] |
134 type Output = Loc<S::Type, N>; |
158 impl<'a, F : Float, S, const N : usize> Lipschitz<L2> |
135 #[inline] |
159 for Differential<'a, Loc<F, N>, HatConv<S, N>> |
136 fn differential(&self, y : Loc<S::Type, N>) -> Self::Output { |
160 where S : Constant<Type=F> { |
137 self.differential(&y) |
161 type FloatType = F; |
138 } |
162 |
139 } |
163 #[inline] |
|
164 fn lipschitz_factor(&self, _l2 : L2) -> Option<F> { |
|
165 let h = self.base_fn(); |
|
166 let σ = h.radius(); |
|
167 Some(product_differential_lipschitz_factor::<F, N>( |
|
168 h.value_1d_σ1(0.0) / σ, |
|
169 h.lipschitz_1d_σ1() / (σ*σ), |
|
170 h.maxabsdiff_1d_σ1() / (σ*σ), |
|
171 h.lipschitz_diff_1d_σ1() / (σ*σ), |
|
172 )) |
|
173 } |
|
174 } |
|
175 |
140 |
176 |
141 #[replace_float_literals(S::Type::cast_from(literal))] |
177 #[replace_float_literals(S::Type::cast_from(literal))] |
142 impl<'a, F : Float, S, const N : usize> HatConv<S, N> |
178 impl<'a, F : Float, S, const N : usize> HatConv<S, N> |
143 where S : Constant<Type=F> { |
179 where S : Constant<Type=F> { |
144 /// Computes the value of the kernel for $n=1$ with $σ=1$. |
180 /// Computes the value of the kernel for $n=1$ with $σ=1$. |
171 #[inline] |
207 #[inline] |
172 fn lipschitz_1d_σ1(&self) -> F { |
208 fn lipschitz_1d_σ1(&self) -> F { |
173 // Maximal absolute differential achieved at ±0.5 by diff_1d_σ1 analysis |
209 // Maximal absolute differential achieved at ±0.5 by diff_1d_σ1 analysis |
174 2.0 |
210 2.0 |
175 } |
211 } |
|
212 |
|
213 /// Computes the maximum absolute differential of the kernel for $n=1$ with $σ=1$. |
|
214 #[inline] |
|
215 fn maxabsdiff_1d_σ1(&self) -> F { |
|
216 // Maximal absolute differential achieved at ±0.5 by diff_1d_σ1 analysis |
|
217 2.0 |
|
218 } |
|
219 |
|
220 /// Computes the second differential of the kernel for $n=1$ with $σ=1$. |
|
221 #[inline] |
|
222 #[allow(dead_code)] |
|
223 fn diff2_1d_σ1(&self, x : F) -> F { |
|
224 let y = x.abs(); |
|
225 if y >= 1.0 { |
|
226 0.0 |
|
227 } else if y > 0.5 { |
|
228 - 16.0 * (y - 1.0) |
|
229 } else /* 0 ≤ y ≤ 0.5 */ { |
|
230 48.0 * y - 16.0 |
|
231 } |
|
232 } |
|
233 |
|
234 /// Computes the differential of the kernel for $n=1$ with $σ=1$. |
|
235 #[inline] |
|
236 fn lipschitz_diff_1d_σ1(&self) -> F { |
|
237 // Maximal absolute second differential achieved at 0 by diff2_1d_σ1 analysis |
|
238 16.0 |
|
239 } |
176 } |
240 } |
177 |
241 |
178 impl<'a, S, const N : usize> Support<S::Type, N> for HatConv<S, N> |
242 impl<'a, S, const N : usize> Support<S::Type, N> for HatConv<S, N> |
179 where S : Constant { |
243 where S : Constant { |
180 #[inline] |
244 #[inline] |
233 self.bounds().upper() |
297 self.bounds().upper() |
234 } |
298 } |
235 } |
299 } |
236 |
300 |
237 #[replace_float_literals(F::cast_from(literal))] |
301 #[replace_float_literals(F::cast_from(literal))] |
238 impl<'a, F : Float, R, C, const N : usize> Apply<&'a Loc<F, N>> |
302 impl<'a, F : Float, R, C, const N : usize> Mapping<Loc<F, N>> |
239 for Convolution<CubeIndicator<R, N>, HatConv<C, N>> |
303 for Convolution<CubeIndicator<R, N>, HatConv<C, N>> |
240 where R : Constant<Type=F>, |
304 where R : Constant<Type=F>, |
241 C : Constant<Type=F> { |
305 C : Constant<Type=F> { |
242 |
306 |
243 type Output = F; |
307 type Codomain = F; |
244 |
308 |
245 #[inline] |
309 #[inline] |
246 fn apply(&self, y : &'a Loc<F, N>) -> F { |
310 fn apply<I : Instance<Loc<F, N>>>(&self, y : I) -> F { |
247 let Convolution(ref ind, ref hatconv) = self; |
311 let Convolution(ref ind, ref hatconv) = self; |
248 let β = ind.r.value(); |
312 let β = ind.r.value(); |
249 let σ = hatconv.radius(); |
313 let σ = hatconv.radius(); |
250 |
314 |
251 // This is just a product of one-dimensional versions |
315 // This is just a product of one-dimensional versions |
252 y.product_map(|x| { |
316 y.cow().product_map(|x| { |
253 // With $u_σ(x) = u_1(x/σ)/σ$ the normalised hat convolution |
317 // With $u_σ(x) = u_1(x/σ)/σ$ the normalised hat convolution |
254 // we have |
318 // we have |
255 // $$ |
319 // $$ |
256 // [χ_{-β,β} * u_σ](x) |
320 // [χ_{-β,β} * u_σ](x) |
257 // = ∫_{x-β}^{x+β} u_σ(z) d z |
321 // = ∫_{x-β}^{x+β} u_σ(z) d z |
262 self.value_1d_σ1(x / σ, β / σ) |
326 self.value_1d_σ1(x / σ, β / σ) |
263 }) |
327 }) |
264 } |
328 } |
265 } |
329 } |
266 |
330 |
267 impl<'a, F : Float, R, C, const N : usize> Apply<Loc<F, N>> |
331 #[replace_float_literals(F::cast_from(literal))] |
|
332 impl<'a, F : Float, R, C, const N : usize> DifferentiableImpl<Loc<F, N>> |
268 for Convolution<CubeIndicator<R, N>, HatConv<C, N>> |
333 for Convolution<CubeIndicator<R, N>, HatConv<C, N>> |
269 where R : Constant<Type=F>, |
334 where R : Constant<Type=F>, |
270 C : Constant<Type=F> { |
335 C : Constant<Type=F> { |
271 |
336 |
272 type Output = F; |
337 type Derivative = Loc<F, N>; |
273 |
338 |
274 #[inline] |
339 #[inline] |
275 fn apply(&self, y : Loc<F, N>) -> F { |
340 fn differential_impl<I : Instance<Loc<F, N>>>(&self, y0 : I) -> Loc<F, N> { |
276 self.apply(&y) |
341 let y = y0.cow(); |
277 } |
|
278 } |
|
279 |
|
280 #[replace_float_literals(F::cast_from(literal))] |
|
281 impl<'a, F : Float, R, C, const N : usize> Differentiable<&'a Loc<F, N>> |
|
282 for Convolution<CubeIndicator<R, N>, HatConv<C, N>> |
|
283 where R : Constant<Type=F>, |
|
284 C : Constant<Type=F> { |
|
285 |
|
286 type Output = Loc<F, N>; |
|
287 |
|
288 #[inline] |
|
289 fn differential(&self, y : &'a Loc<F, N>) -> Loc<F, N> { |
|
290 let Convolution(ref ind, ref hatconv) = self; |
342 let Convolution(ref ind, ref hatconv) = self; |
291 let β = ind.r.value(); |
343 let β = ind.r.value(); |
292 let σ = hatconv.radius(); |
344 let σ = hatconv.radius(); |
293 let σ2 = σ * σ; |
345 let σ2 = σ * σ; |
294 |
346 |
295 let vs = y.map(|x| { |
347 let vs = y.map(|x| { |
296 self.value_1d_σ1(x / σ, β / σ) |
348 self.value_1d_σ1(x / σ, β / σ) |
297 }); |
349 }); |
298 product_differential(y, &vs, |x| { |
350 product_differential(&*y, &vs, |x| { |
299 self.diff_1d_σ1(x / σ, β / σ) / σ2 |
351 self.diff_1d_σ1(x / σ, β / σ) / σ2 |
300 }) |
352 }) |
301 } |
353 } |
302 } |
354 } |
303 |
355 |
304 impl<'a, F : Float, R, C, const N : usize> Differentiable<Loc<F, N>> |
|
305 for Convolution<CubeIndicator<R, N>, HatConv<C, N>> |
|
306 where R : Constant<Type=F>, |
|
307 C : Constant<Type=F> { |
|
308 |
|
309 type Output = Loc<F, N>; |
|
310 |
|
311 #[inline] |
|
312 fn differential(&self, y : Loc<F, N>) -> Loc<F, N> { |
|
313 self.differential(&y) |
|
314 } |
|
315 } |
|
316 |
356 |
317 /// Integrate $f$, whose support is $[c, d]$, on $[a, b]$. |
357 /// Integrate $f$, whose support is $[c, d]$, on $[a, b]$. |
318 /// If $b > d$, add $g()$ to the result. |
358 /// If $b > d$, add $g()$ to the result. |
319 #[inline] |
359 #[inline] |
320 #[replace_float_literals(F::cast_from(literal))] |
360 #[replace_float_literals(F::cast_from(literal))] |
413 ) |
453 ) |
414 ) |
454 ) |
415 } |
455 } |
416 } |
456 } |
417 |
457 |
|
458 /* |
|
459 impl<'a, F : Float, R, C, const N : usize> Lipschitz<L2> |
|
460 for Differential<Loc<F, N>, Convolution<CubeIndicator<R, N>, HatConv<C, N>>> |
|
461 where R : Constant<Type=F>, |
|
462 C : Constant<Type=F> { |
|
463 |
|
464 type FloatType = F; |
|
465 |
|
466 #[inline] |
|
467 fn lipschitz_factor(&self, _l2 : L2) -> Option<F> { |
|
468 dbg!("unimplemented"); |
|
469 None |
|
470 } |
|
471 } |
|
472 */ |
|
473 |
418 impl<F : Float, R, C, const N : usize> |
474 impl<F : Float, R, C, const N : usize> |
419 Convolution<CubeIndicator<R, N>, HatConv<C, N>> |
475 Convolution<CubeIndicator<R, N>, HatConv<C, N>> |
420 where R : Constant<Type=F>, |
476 where R : Constant<Type=F>, |
421 C : Constant<Type=F> { |
477 C : Constant<Type=F> { |
422 |
478 |