79 fn apply(&self, y : Loc<S::Type, N>) -> Self::Output { |
80 fn apply(&self, y : Loc<S::Type, N>) -> Self::Output { |
80 self.apply(&y) |
81 self.apply(&y) |
81 } |
82 } |
82 } |
83 } |
83 |
84 |
|
85 #[replace_float_literals(S::Type::cast_from(literal))] |
|
86 impl<S, const N : usize> Lipschitz<L1> for HatConv<S, N> |
|
87 where S : Constant { |
|
88 type FloatType = S::Type; |
|
89 #[inline] |
|
90 fn lipschitz_factor(&self, L1 : L1) -> Option<Self::FloatType> { |
|
91 // For any ψ_i, we have |
|
92 // ∏_{i=1}^N ψ_i(x_i) - ∏_{i=1}^N ψ_i(y_i) |
|
93 // = [ψ_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)] |
|
95 // = ∑_{j=1}^N [ψ_j(x_j)-ψ_j(y_j)]∏_{i > j} ψ_i(x_i) ∏_{i < j} ψ_i(y_i) |
|
96 // Thus |
|
97 // |∏_{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| |
|
99 let σ = self.radius(); |
|
100 Some((self.lipschitz_1d_σ1() / (σ*σ)) * (self.value_1d_σ1(0.0) / σ)) |
|
101 } |
|
102 } |
|
103 |
|
104 impl<S, const N : usize> Lipschitz<L2> for HatConv<S, N> |
|
105 where S : Constant { |
|
106 type FloatType = S::Type; |
|
107 #[inline] |
|
108 fn lipschitz_factor(&self, L2 : L2) -> Option<Self::FloatType> { |
|
109 self.lipschitz_factor(L1).map(|l1| l1 * <S::Type>::cast_from(N).sqrt()) |
|
110 } |
|
111 } |
|
112 |
|
113 |
|
114 impl<'a, S, const N : usize> Differentiable<&'a Loc<S::Type, N>> for HatConv<S, N> |
|
115 where S : Constant { |
|
116 type Output = Loc<S::Type, N>; |
|
117 #[inline] |
|
118 fn differential(&self, y : &'a Loc<S::Type, N>) -> Self::Output { |
|
119 let σ = self.radius(); |
|
120 let σ2 = σ * σ; |
|
121 let vs = y.map(|x| { |
|
122 self.value_1d_σ1(x / σ) / σ |
|
123 }); |
|
124 product_differential(y, &vs, |x| { |
|
125 self.diff_1d_σ1(x / σ) / σ2 |
|
126 }) |
|
127 } |
|
128 } |
|
129 |
|
130 impl<'a, S, const N : usize> Differentiable<Loc<S::Type, N>> for HatConv<S, N> |
|
131 where S : Constant { |
|
132 type Output = Loc<S::Type, N>; |
|
133 #[inline] |
|
134 fn differential(&self, y : Loc<S::Type, N>) -> Self::Output { |
|
135 self.differential(&y) |
|
136 } |
|
137 } |
84 |
138 |
85 #[replace_float_literals(S::Type::cast_from(literal))] |
139 #[replace_float_literals(S::Type::cast_from(literal))] |
86 impl<'a, F : Float, S, const N : usize> HatConv<S, N> |
140 impl<'a, F : Float, S, const N : usize> HatConv<S, N> |
87 where S : Constant<Type=F> { |
141 where S : Constant<Type=F> { |
88 /// Computes the value of the kernel for $n=1$ with $σ=1$. |
142 /// Computes the value of the kernel for $n=1$ with $σ=1$. |
94 } else if y > 0.5 { |
148 } else if y > 0.5 { |
95 - (8.0/3.0) * (y - 1.0).powi(3) |
149 - (8.0/3.0) * (y - 1.0).powi(3) |
96 } else /* 0 ≤ y ≤ 0.5 */ { |
150 } else /* 0 ≤ y ≤ 0.5 */ { |
97 (4.0/3.0) + 8.0 * y * y * (y - 1.0) |
151 (4.0/3.0) + 8.0 * y * y * (y - 1.0) |
98 } |
152 } |
|
153 } |
|
154 |
|
155 /// Computes the differential of the kernel for $n=1$ with $σ=1$. |
|
156 #[inline] |
|
157 fn diff_1d_σ1(&self, x : F) -> F { |
|
158 let y = x.abs(); |
|
159 if y >= 1.0 { |
|
160 0.0 |
|
161 } else if y > 0.5 { |
|
162 - 8.0 * (y - 1.0).powi(2) |
|
163 } else /* 0 ≤ y ≤ 0.5 */ { |
|
164 (24.0 * y - 16.0) * y |
|
165 } |
|
166 } |
|
167 |
|
168 /// Computes the Lipschitz factor of the kernel for $n=1$ with $σ=1$. |
|
169 #[inline] |
|
170 fn lipschitz_1d_σ1(&self) -> F { |
|
171 // Maximal absolute differential achieved at ±0.5 by diff_1d_σ1 analysis |
|
172 2.0 |
99 } |
173 } |
100 } |
174 } |
101 |
175 |
102 impl<'a, S, const N : usize> Support<S::Type, N> for HatConv<S, N> |
176 impl<'a, S, const N : usize> Support<S::Type, N> for HatConv<S, N> |
103 where S : Constant { |
177 where S : Constant { |
199 fn apply(&self, y : Loc<F, N>) -> F { |
273 fn apply(&self, y : Loc<F, N>) -> F { |
200 self.apply(&y) |
274 self.apply(&y) |
201 } |
275 } |
202 } |
276 } |
203 |
277 |
|
278 #[replace_float_literals(F::cast_from(literal))] |
|
279 impl<'a, F : Float, R, C, const N : usize> Differentiable<&'a Loc<F, N>> |
|
280 for Convolution<CubeIndicator<R, N>, HatConv<C, N>> |
|
281 where R : Constant<Type=F>, |
|
282 C : Constant<Type=F> { |
|
283 |
|
284 type Output = Loc<F, N>; |
|
285 |
|
286 #[inline] |
|
287 fn differential(&self, y : &'a Loc<F, N>) -> Loc<F, N> { |
|
288 let Convolution(ref ind, ref hatconv) = self; |
|
289 let β = ind.r.value(); |
|
290 let σ = hatconv.radius(); |
|
291 let σ2 = σ * σ; |
|
292 |
|
293 let vs = y.map(|x| { |
|
294 self.value_1d_σ1(x / σ, β / σ) |
|
295 }); |
|
296 product_differential(y, &vs, |x| { |
|
297 self.diff_1d_σ1(x / σ, β / σ) / σ2 |
|
298 }) |
|
299 } |
|
300 } |
|
301 |
|
302 impl<'a, F : Float, R, C, const N : usize> Differentiable<Loc<F, N>> |
|
303 for Convolution<CubeIndicator<R, N>, HatConv<C, N>> |
|
304 where R : Constant<Type=F>, |
|
305 C : Constant<Type=F> { |
|
306 |
|
307 type Output = Loc<F, N>; |
|
308 |
|
309 #[inline] |
|
310 fn differential(&self, y : Loc<F, N>) -> Loc<F, N> { |
|
311 self.differential(&y) |
|
312 } |
|
313 } |
|
314 |
|
315 /// Integrate $f$, whose support is $[c, d]$, on $[a, b]$. |
|
316 /// If $b > d$, add $g()$ to the result. |
|
317 #[inline] |
|
318 #[replace_float_literals(F::cast_from(literal))] |
|
319 fn i<F: Float>(a : F, b : F, c : F, d : F, f : impl Fn(F) -> F, |
|
320 g : impl Fn() -> F) -> F { |
|
321 if b < c { |
|
322 0.0 |
|
323 } else if b <= d { |
|
324 if a <= c { |
|
325 f(b) - f(c) |
|
326 } else { |
|
327 f(b) - f(a) |
|
328 } |
|
329 } else /* b > d */ { |
|
330 g() + if a <= c { |
|
331 f(d) - f(c) |
|
332 } else if a < d { |
|
333 f(d) - f(a) |
|
334 } else { |
|
335 0.0 |
|
336 } |
|
337 } |
|
338 } |
204 |
339 |
205 #[replace_float_literals(F::cast_from(literal))] |
340 #[replace_float_literals(F::cast_from(literal))] |
206 impl<F : Float, C, R, const N : usize> Convolution<CubeIndicator<R, N>, HatConv<C, N>> |
341 impl<F : Float, C, R, const N : usize> Convolution<CubeIndicator<R, N>, HatConv<C, N>> |
207 where R : Constant<Type=F>, |
342 where R : Constant<Type=F>, |
208 C : Constant<Type=F> { |
343 C : Constant<Type=F> { |
|
344 |
|
345 /// Calculates the value of the 1D hat convolution further convolved by a interval indicator. |
|
346 /// As both functions are piecewise polynomials, this is implemented by explicit integral over |
|
347 /// all subintervals of polynomiality of the cube indicator, using easily formed |
|
348 /// antiderivatives. |
209 #[inline] |
349 #[inline] |
210 pub fn value_1d_σ1(&self, x : F, β : F) -> F { |
350 pub fn value_1d_σ1(&self, x : F, β : F) -> F { |
211 // The integration interval |
351 // The integration interval |
212 let a = x - β; |
352 let a = x - β; |
213 let b = x + β; |
353 let b = x + β; |
216 fn pow4<F : Float>(x : F) -> F { |
356 fn pow4<F : Float>(x : F) -> F { |
217 let y = x * x; |
357 let y = x * x; |
218 y * y |
358 y * y |
219 } |
359 } |
220 |
360 |
221 /// Integrate $f$, whose support is $[c, d]$, on $[a, b]$. |
|
222 /// If $b > d$, add $g()$ to the result. |
|
223 #[inline] |
|
224 fn i<F: Float>(a : F, b : F, c : F, d : F, f : impl Fn(F) -> F, |
|
225 g : impl Fn() -> F) -> F { |
|
226 if b < c { |
|
227 0.0 |
|
228 } else if b <= d { |
|
229 if a <= c { |
|
230 f(b) - f(c) |
|
231 } else { |
|
232 f(b) - f(a) |
|
233 } |
|
234 } else /* b > d */ { |
|
235 g() + if a <= c { |
|
236 f(d) - f(c) |
|
237 } else if a < d { |
|
238 f(d) - f(a) |
|
239 } else { |
|
240 0.0 |
|
241 } |
|
242 } |
|
243 } |
|
244 |
|
245 // Observe the factor 1/6 at the front from the antiderivatives below. |
361 // Observe the factor 1/6 at the front from the antiderivatives below. |
246 // The factor 4 is from normalisation of the original function. |
362 // The factor 4 is from normalisation of the original function. |
247 (4.0/6.0) * i(a, b, -1.0, -0.5, |
363 (4.0/6.0) * i(a, b, -1.0, -0.5, |
248 // (2/3) (y+1)^3 on -1 < y ≤ - 1/2 |
364 // (2/3) (y+1)^3 on -1 < y ≤ -1/2 |
249 // The antiderivative is (2/12)(y+1)^4 = (1/6)(y+1)^4 |
365 // The antiderivative is (2/12)(y+1)^4 = (1/6)(y+1)^4 |
250 |y| pow4(y+1.0), |
366 |y| pow4(y+1.0), |
251 || i(a, b, -0.5, 0.0, |
367 || i(a, b, -0.5, 0.0, |
252 // -2 y^3 - 2 y^2 + 1/3 on -1/2 < y ≤ 0 |
368 // -2 y^3 - 2 y^2 + 1/3 on -1/2 < y ≤ 0 |
253 // The antiderivative is -1/2 y^4 - 2/3 y^3 + 1/3 y |
369 // The antiderivative is -1/2 y^4 - 2/3 y^3 + 1/3 y |
264 ) |
380 ) |
265 ) |
381 ) |
266 ) |
382 ) |
267 ) |
383 ) |
268 } |
384 } |
|
385 |
|
386 /// Calculates the derivative of the 1D hat convolution further convolved by a interval |
|
387 /// indicator. The implementation is similar to [`Self::value_1d_σ1`], using the fact that |
|
388 /// $(θ * ψ)' = θ * ψ'$. |
|
389 #[inline] |
|
390 pub fn diff_1d_σ1(&self, x : F, β : F) -> F { |
|
391 // The integration interval |
|
392 let a = x - β; |
|
393 let b = x + β; |
|
394 |
|
395 // The factor 4 is from normalisation of the original function. |
|
396 4.0 * i(a, b, -1.0, -0.5, |
|
397 // (2/3) (y+1)^3 on -1 < y ≤ -1/2 |
|
398 |y| (2.0/3.0) * (y + 1.0).powi(3), |
|
399 || i(a, b, -0.5, 0.0, |
|
400 // -2 y^3 - 2 y^2 + 1/3 on -1/2 < y ≤ 0 |
|
401 |y| -2.0*(y - 1.0) * y * y + (1.0/3.0), |
|
402 || i(a, b, 0.0, 0.5, |
|
403 // 2 y^3 - 2 y^2 + 1/3 on 0 < y < 1/2 |
|
404 |y| 2.0*(y - 1.0) * y * y + (1.0/3.0), |
|
405 || i(a, b, 0.5, 1.0, |
|
406 // -(2/3) (y-1)^3 on 1/2 < y ≤ 1 |
|
407 |y| -(2.0/3.0) * (y - 1.0).powi(3), |
|
408 || 0.0 |
|
409 ) |
|
410 ) |
|
411 ) |
|
412 ) |
|
413 } |
269 } |
414 } |
270 |
415 |
271 impl<F : Float, R, C, const N : usize> |
416 impl<F : Float, R, C, const N : usize> |
272 Convolution<CubeIndicator<R, N>, HatConv<C, N>> |
417 Convolution<CubeIndicator<R, N>, HatConv<C, N>> |
273 where R : Constant<Type=F>, |
418 where R : Constant<Type=F>, |