| 95 type Codomain = S::Type; |
95 type Codomain = S::Type; |
| 96 |
96 |
| 97 #[inline] |
97 #[inline] |
| 98 fn apply<I: Instance<Loc<N, S::Type>>>(&self, y: I) -> Self::Codomain { |
98 fn apply<I: Instance<Loc<N, S::Type>>>(&self, y: I) -> Self::Codomain { |
| 99 let σ = self.radius(); |
99 let σ = self.radius(); |
| 100 y.decompose().product_map(|x| self.value_1d_σ1(x / σ) / σ) |
100 y.decompose().product_map(|x| self.value_1d_σ1(x / σ)) / σ.powi(N as i32) |
| 101 } |
101 } |
| 102 } |
102 } |
| 103 |
103 |
| 104 #[replace_float_literals(S::Type::cast_from(literal))] |
104 #[replace_float_literals(S::Type::cast_from(literal))] |
| 105 impl<S, const N: usize> Lipschitz<L1> for HatConv<S, N> |
105 impl<S, const N: usize> Lipschitz<L2> for HatConv<S, N> |
| 106 where |
106 where |
| 107 S: Constant, |
107 S: Constant, |
| 108 { |
108 { |
| 109 type FloatType = S::Type; |
109 type FloatType = S::Type; |
| 110 #[inline] |
110 #[inline] |
| 111 fn lipschitz_factor(&self, L1: L1) -> DynResult<Self::FloatType> { |
111 fn lipschitz_factor(&self, _L2: L2) -> DynResult<Self::FloatType> { |
| 112 // For any ψ_i, we have |
112 // For arbitrary ψ(x) = ∏_{i=1}^n ψ_i(x_i), we have |
| 113 // ∏_{i=1}^N ψ_i(x_i) - ∏_{i=1}^N ψ_i(y_i) |
113 // ψ(x) - ψ(y) = ∑_i [ψ_i(x_i)-ψ_i(y_i)] ∏_{j < i} ψ_j(y_j) ∏_{j > i} ψ_j(x_j) |
| 114 // = [ψ_1(x_1)-ψ_1(y_1)] ∏_{i=2}^N ψ_i(x_i) |
114 // by a simple recursive argument. In particular, if ψ_i=g for all i, j, we have |
| 115 // + ψ_1(y_1)[ ∏_{i=2}^N ψ_i(x_i) - ∏_{i=2}^N ψ_i(y_i)] |
115 // |ψ(x) - ψ(y)| ≤ ∑_i L_g|x_i-y_i| M_g^{n-1} ≤ √n L_g M_g^{n-1} |x-y|₂ |
| 116 // = ∑_{j=1}^N [ψ_j(x_j)-ψ_j(y_j)]∏_{i > j} ψ_i(x_i) ∏_{i < j} ψ_i(y_i) |
116 // where L_g is the Lipschitz factor of g, and M_g a bound on it. |
| 117 // Thus |
|
| 118 // |∏_{i=1}^N ψ_i(x_i) - ∏_{i=1}^N ψ_i(y_i)| |
|
| 119 // ≤ ∑_{j=1}^N |ψ_j(x_j)-ψ_j(y_j)| ∏_{j ≠ i} \max_j |ψ_j| |
|
| 120 let σ = self.radius(); |
117 let σ = self.radius(); |
| 121 let l1d = self.lipschitz_1d_σ1() / (σ * σ); |
118 let l1d = self.lipschitz_1d_σ1(); |
| 122 let m1d = self.value_1d_σ1(0.0) / σ; |
119 let m1d = self.value_1d_σ1(0.0); |
| 123 Ok(l1d * m1d.powi(N as i32 - 1)) |
120 Ok( |
| 124 } |
121 S::Type::cast_from(N).sqrt() * l1d * m1d.powi((N - 1) as i32) |
| 125 } |
122 / σ.powi((N - 1 + 2) as i32), |
| 126 |
123 ) |
| 127 impl<S, const N: usize> Lipschitz<L2> for HatConv<S, N> |
|
| 128 where |
|
| 129 S: Constant, |
|
| 130 { |
|
| 131 type FloatType = S::Type; |
|
| 132 #[inline] |
|
| 133 fn lipschitz_factor(&self, L2: L2) -> DynResult<Self::FloatType> { |
|
| 134 self.lipschitz_factor(L1) |
|
| 135 .map(|l1| l1 * <S::Type>::cast_from(N).sqrt()) |
|
| 136 } |
124 } |
| 137 } |
125 } |
| 138 |
126 |
| 139 impl<'a, S, const N: usize> DifferentiableImpl<Loc<N, S::Type>> for HatConv<S, N> |
127 impl<'a, S, const N: usize> DifferentiableImpl<Loc<N, S::Type>> for HatConv<S, N> |
| 140 where |
128 where |
| 144 |
132 |
| 145 #[inline] |
133 #[inline] |
| 146 fn differential_impl<I: Instance<Loc<N, S::Type>>>(&self, y0: I) -> Self::Derivative { |
134 fn differential_impl<I: Instance<Loc<N, S::Type>>>(&self, y0: I) -> Self::Derivative { |
| 147 let y = y0.decompose(); |
135 let y = y0.decompose(); |
| 148 let σ = self.radius(); |
136 let σ = self.radius(); |
| 149 let σ2 = σ * σ; |
137 let tmp = y.map(|x| x / σ); |
| 150 let vs = y.map(|x| self.value_1d_σ1(x / σ) / σ); |
138 let vs = tmp.map(|x| self.value_1d_σ1(x)); |
| 151 product_differential(&*y, &vs, |x| self.diff_1d_σ1(x / σ) / σ2) |
139 product_differential(&tmp, &vs, |x| self.diff_1d_σ1(x)) / σ.powi((N + 1) as i32) |
| 152 } |
140 } |
| 153 } |
141 } |
| 154 |
142 |
| 155 #[replace_float_literals(S::Type::cast_from(literal))] |
143 #[replace_float_literals(S::Type::cast_from(literal))] |
| 156 impl<'a, F: Float, S, const N: usize> LipschitzDifferentiableImpl<Loc<N, S::Type>, L2> |
144 impl<'a, F: Float, S, const N: usize> LipschitzDifferentiableImpl<Loc<N, S::Type>, L2> |
| 162 |
150 |
| 163 #[inline] |
151 #[inline] |
| 164 fn diff_lipschitz_factor(&self, _l2: L2) -> DynResult<F> { |
152 fn diff_lipschitz_factor(&self, _l2: L2) -> DynResult<F> { |
| 165 let σ = self.radius(); |
153 let σ = self.radius(); |
| 166 product_differential_lipschitz_factor::<F, N>( |
154 product_differential_lipschitz_factor::<F, N>( |
| 167 self.value_1d_σ1(0.0) / σ, |
155 self.value_1d_σ1(0.0), |
| 168 self.lipschitz_1d_σ1() / (σ * σ), |
156 self.lipschitz_1d_σ1(), |
| 169 self.maxabsdiff_1d_σ1() / (σ * σ), |
157 self.maxabsdiff_1d_σ1(), |
| 170 self.lipschitz_diff_1d_σ1() / (σ * σ), |
158 self.lipschitz_diff_1d_σ1(), |
| 171 ) |
159 ) |
| |
160 .map(|l| l / σ.powi((N + 2) as i32)) |
| |
161 // We have f(x)=f₀(x/σ)/σ^N, where f₀(z)=∏_{i=1}^N f₁(z_i). |
| |
162 // Thus |f'(x)-f'(y)| = |f₀'(x/σ)-f₀'(y/σ)|/σ^{N+1} ≤ L_{f₀'}/σ^{N+2}. |
| 172 } |
163 } |
| 173 } |
164 } |
| 174 |
165 |
| 175 #[replace_float_literals(S::Type::cast_from(literal))] |
166 #[replace_float_literals(S::Type::cast_from(literal))] |
| 176 impl<'a, F: Float, S, const N: usize> HatConv<S, N> |
167 impl<'a, F: Float, S, const N: usize> HatConv<S, N> |
| 193 } |
184 } |
| 194 |
185 |
| 195 /// Computes the differential of the kernel for $n=1$ with $σ=1$. |
186 /// Computes the differential of the kernel for $n=1$ with $σ=1$. |
| 196 #[inline] |
187 #[inline] |
| 197 fn diff_1d_σ1(&self, x: F) -> F { |
188 fn diff_1d_σ1(&self, x: F) -> F { |
| 198 let y = x.abs(); |
189 if x >= 1.0 || x <= -1.0 { |
| 199 if y >= 1.0 { |
|
| 200 0.0 |
190 0.0 |
| 201 } else if y > 0.5 { |
191 } else if x > 0.5 { |
| 202 -8.0 * (y - 1.0).powi(2) |
192 -8.0 * (x - 1.0).powi(2) |
| 203 } else |
193 } else if x < -0.5 { |
| 204 /* 0 ≤ y ≤ 0.5 */ |
194 8.0 * (x + 1.0).powi(2) |
| 205 { |
195 } else { |
| 206 (24.0 * y - 16.0) * y |
196 /* 0 ≤ y ≤ 0.5 */ |
| |
197 (24.0 * x.abs() - 16.0) * x |
| 207 } |
198 } |
| 208 } |
199 } |
| 209 |
200 |
| 210 /// Computes the Lipschitz factor of the kernel for $n=1$ with $σ=1$. |
201 /// Computes the Lipschitz factor of the kernel for $n=1$ with $σ=1$. |
| 211 #[inline] |
202 #[inline] |
| 217 /// Computes the maximum absolute differential of the kernel for $n=1$ with $σ=1$. |
208 /// Computes the maximum absolute differential of the kernel for $n=1$ with $σ=1$. |
| 218 #[inline] |
209 #[inline] |
| 219 fn maxabsdiff_1d_σ1(&self) -> F { |
210 fn maxabsdiff_1d_σ1(&self) -> F { |
| 220 // Maximal absolute differential achieved at ±0.5 by diff_1d_σ1 analysis |
211 // Maximal absolute differential achieved at ±0.5 by diff_1d_σ1 analysis |
| 221 2.0 |
212 2.0 |
| 222 } |
|
| 223 |
|
| 224 /// Computes the second differential of the kernel for $n=1$ with $σ=1$. |
|
| 225 #[inline] |
|
| 226 #[allow(dead_code)] |
|
| 227 fn diff2_1d_σ1(&self, x: F) -> F { |
|
| 228 let y = x.abs(); |
|
| 229 if y >= 1.0 { |
|
| 230 0.0 |
|
| 231 } else if y > 0.5 { |
|
| 232 -16.0 * (y - 1.0) |
|
| 233 } else |
|
| 234 /* 0 ≤ y ≤ 0.5 */ |
|
| 235 { |
|
| 236 48.0 * y - 16.0 |
|
| 237 } |
|
| 238 } |
213 } |
| 239 |
214 |
| 240 /// Computes the differential of the kernel for $n=1$ with $σ=1$. |
215 /// Computes the differential of the kernel for $n=1$ with $σ=1$. |
| 241 #[inline] |
216 #[inline] |
| 242 fn lipschitz_diff_1d_σ1(&self) -> F { |
217 fn lipschitz_diff_1d_σ1(&self) -> F { |
| 330 // $$ |
305 // $$ |
| 331 // [χ_{-β,β} * u_σ](x) |
306 // [χ_{-β,β} * u_σ](x) |
| 332 // = ∫_{x-β}^{x+β} u_σ(z) d z |
307 // = ∫_{x-β}^{x+β} u_σ(z) d z |
| 333 // = (1/σ)∫_{x-β}^{x+β} u_1(z/σ) d z |
308 // = (1/σ)∫_{x-β}^{x+β} u_1(z/σ) d z |
| 334 // = ∫_{(x-β)/σ}^{(x+β)/σ} u_1(z) d z |
309 // = ∫_{(x-β)/σ}^{(x+β)/σ} u_1(z) d z |
| 335 // = [χ_{-β/σ, β/σ} * u_1](x/σ) |
310 // = (χ_{[-β/σ, β/σ]} * u_1)(x/σ) |
| 336 // $$ |
311 // $$ |
| 337 self.value_1d_σ1(x / σ, β / σ) |
312 self.value_1d_σ1(x / σ, β / σ) |
| 338 }) |
313 }) |
| 339 } |
314 } |
| 340 } |
315 } |
| 352 fn differential_impl<I: Instance<Loc<N, F>>>(&self, y0: I) -> Loc<N, F> { |
327 fn differential_impl<I: Instance<Loc<N, F>>>(&self, y0: I) -> Loc<N, F> { |
| 353 let y = y0.decompose(); |
328 let y = y0.decompose(); |
| 354 let Convolution(ref ind, ref hatconv) = self; |
329 let Convolution(ref ind, ref hatconv) = self; |
| 355 let β = ind.r.value(); |
330 let β = ind.r.value(); |
| 356 let σ = hatconv.radius(); |
331 let σ = hatconv.radius(); |
| 357 let σ2 = σ * σ; |
|
| 358 |
332 |
| 359 let vs = y.map(|x| self.value_1d_σ1(x / σ, β / σ)); |
333 let vs = y.map(|x| self.value_1d_σ1(x / σ, β / σ)); |
| 360 product_differential(&*y, &vs, |x| self.diff_1d_σ1(x / σ, β / σ) / σ2) |
334 product_differential(&*y, &vs, |x| self.diff_1d_σ1(x / σ, β / σ)) / σ |
| 361 } |
335 } |
| 362 } |
336 } |
| 363 |
337 |
| 364 /// Integrate $f$, whose support is $[c, d]$, on $[a, b]$. |
338 /// Integrate $f'$, whose support is $[c, d]$, on $[a, b]$. |
| |
339 /// The value $f$ is given, not the derivative. |
| 365 /// If $b > d$, add $g()$ to the result. |
340 /// If $b > d$, add $g()$ to the result. |
| 366 #[inline] |
341 #[inline] |
| 367 #[replace_float_literals(F::cast_from(literal))] |
342 #[replace_float_literals(F::cast_from(literal))] |
| 368 fn i<F: Float>(a: F, b: F, c: F, d: F, f: impl Fn(F) -> F, g: impl Fn() -> F) -> F { |
343 fn i<F: Float>(a: F, b: F, c: F, d: F, f: impl Fn(F) -> F, g: impl Fn() -> F) -> F { |
| 369 if b < c { |
344 if b < c { |
| 401 pub fn value_1d_σ1(&self, x: F, β: F) -> F { |
376 pub fn value_1d_σ1(&self, x: F, β: F) -> F { |
| 402 // The integration interval |
377 // The integration interval |
| 403 let a = x - β; |
378 let a = x - β; |
| 404 let b = x + β; |
379 let b = x + β; |
| 405 |
380 |
| 406 #[inline] |
|
| 407 fn pow4<F: Float>(x: F) -> F { |
|
| 408 let y = x * x; |
|
| 409 y * y |
|
| 410 } |
|
| 411 |
|
| 412 // Observe the factor 1/6 at the front from the antiderivatives below. |
381 // Observe the factor 1/6 at the front from the antiderivatives below. |
| 413 // The factor 4 is from normalisation of the original function. |
382 // The factor 4 is from normalisation of the original function. |
| 414 (4.0 / 6.0) |
383 (4.0 / 6.0) |
| 415 * i( |
384 * i( |
| 416 a, |
385 a, |
| 417 b, |
386 b, |
| 418 -1.0, |
387 -1.0, |
| 419 -0.5, |
388 -0.5, |
| 420 // (2/3) (y+1)^3 on -1 < y ≤ -1/2 |
389 // (2/3) (y+1)^3 on -1 < y ≤ -1/2 |
| 421 // The antiderivative is (2/12)(y+1)^4 = (1/6)(y+1)^4 |
390 // The antiderivative is (2/12)(y+1)^4 = (1/6)(y+1)^4 |
| 422 |y| pow4(y + 1.0), |
391 |y| (y + 1.0).powi(4), |
| 423 || { |
392 || { |
| 424 i( |
393 i( |
| 425 a, |
394 a, |
| 426 b, |
395 b, |
| 427 -0.5, |
396 -0.5, |
| 428 0.0, |
397 0.5, |
| 429 // -2 y^3 - 2 y^2 + 1/3 on -1/2 < y ≤ 0 |
398 // -2 y^3 - 2 y^2 + 1/3 on -1/2 < y ≤ 0 |
| 430 // The antiderivative is -1/2 y^4 - 2/3 y^3 + 1/3 y |
399 // The antiderivative is -1/2 y^4 - 2/3 y^3 + 1/3 y |
| 431 |y| y * (-y * y * (y * 3.0 + 4.0) + 2.0), |
400 // 2 y^3 - 2 y^2 + 1/3 on 0 < y < 1/2 |
| |
401 // The antiderivative is 1/2 y^4 - 2/3 y^3 + 1/3 y |
| |
402 |y| y * (y * y * (y.abs() * 3.0 - 4.0) + 2.0), |
| 432 || { |
403 || { |
| 433 i( |
404 i( |
| 434 a, |
405 a, |
| 435 b, |
406 b, |
| 436 0.0, |
|
| 437 0.5, |
407 0.5, |
| 438 // 2 y^3 - 2 y^2 + 1/3 on 0 < y < 1/2 |
408 1.0, |
| 439 // The antiderivative is 1/2 y^4 - 2/3 y^3 + 1/3 y |
409 // -(2/3) (y-1)^3 on 1/2 < y ≤ 1 |
| 440 |y| y * (y * y * (y * 3.0 - 4.0) + 2.0), |
410 // The antiderivative is -(2/12)(y-1)^4 = -(1/6)(y-1)^4 |
| 441 || { |
411 |y| -(y - 1.0).powi(4), |
| 442 i( |
412 || 0.0, |
| 443 a, |
|
| 444 b, |
|
| 445 0.5, |
|
| 446 1.0, |
|
| 447 // -(2/3) (y-1)^3 on 1/2 < y ≤ 1 |
|
| 448 // The antiderivative is -(2/12)(y-1)^4 = -(1/6)(y-1)^4 |
|
| 449 |y| -pow4(y - 1.0), |
|
| 450 || 0.0, |
|
| 451 ) |
|
| 452 }, |
|
| 453 ) |
413 ) |
| 454 }, |
414 }, |
| 455 ) |
415 ) |
| 456 }, |
416 }, |
| 457 ) |
417 ) |
| 464 pub fn diff_1d_σ1(&self, x: F, β: F) -> F { |
424 pub fn diff_1d_σ1(&self, x: F, β: F) -> F { |
| 465 // The integration interval |
425 // The integration interval |
| 466 let a = x - β; |
426 let a = x - β; |
| 467 let b = x + β; |
427 let b = x + β; |
| 468 |
428 |
| 469 // The factor 4 is from normalisation of the original function. |
429 i( |
| 470 4.0 * i( |
|
| 471 a, |
430 a, |
| 472 b, |
431 b, |
| 473 -1.0, |
432 -1.0, |
| 474 -0.5, |
433 -0.5, |
| 475 // (2/3) (y+1)^3 on -1 < y ≤ -1/2 |
434 // (2/3) (y+1)^3 on -1 < y ≤ -1/2 |
| 476 |y| (2.0 / 3.0) * (y + 1.0).powi(3), |
435 |y| (8.0 / 3.0) * (y + 1.0).powi(3), |
| 477 || { |
436 || { |
| 478 i( |
437 i( |
| 479 a, |
438 a, |
| 480 b, |
439 b, |
| 481 -0.5, |
440 -0.5, |
| 482 0.0, |
441 0.5, |
| 483 // -2 y^3 - 2 y^2 + 1/3 on -1/2 < y ≤ 0 |
442 // 2 y^3 - 2 y^2 + 1/3 on 0 < y < 1/2 |
| 484 |y| -2.0 * (y + 1.0) * y * y + (1.0 / 3.0), |
443 |y| 8.0 * (y.abs() - 1.0) * y * y + (4.0 / 3.0), |
| 485 || { |
444 || { |
| 486 i( |
445 i( |
| 487 a, |
446 a, |
| 488 b, |
447 b, |
| 489 0.0, |
|
| 490 0.5, |
448 0.5, |
| 491 // 2 y^3 - 2 y^2 + 1/3 on 0 < y < 1/2 |
449 1.0, |
| 492 |y| 2.0 * (y - 1.0) * y * y + (1.0 / 3.0), |
450 // -(2/3) (y-1)^3 on 1/2 < y ≤ 1 |
| 493 || { |
451 |y| -(8.0 / 3.0) * (y - 1.0).powi(3), |
| 494 i( |
452 || 0.0, |
| 495 a, |
|
| 496 b, |
|
| 497 0.5, |
|
| 498 1.0, |
|
| 499 // -(2/3) (y-1)^3 on 1/2 < y ≤ 1 |
|
| 500 |y| -(2.0 / 3.0) * (y - 1.0).powi(3), |
|
| 501 || 0.0, |
|
| 502 ) |
|
| 503 }, |
|
| 504 ) |
453 ) |
| 505 }, |
454 }, |
| 506 ) |
455 ) |
| 507 }, |
456 }, |
| 508 ) |
457 ) |
| 523 None |
472 None |
| 524 } |
473 } |
| 525 } |
474 } |
| 526 */ |
475 */ |
| 527 |
476 |
| |
477 #[replace_float_literals(F::cast_from(literal))] |
| 528 impl<F: Float, R, C, const N: usize> Convolution<CubeIndicator<R, N>, HatConv<C, N>> |
478 impl<F: Float, R, C, const N: usize> Convolution<CubeIndicator<R, N>, HatConv<C, N>> |
| 529 where |
479 where |
| 530 R: Constant<Type = F>, |
480 R: Constant<Type = F>, |
| 531 C: Constant<Type = F>, |
481 C: Constant<Type = F>, |
| 532 { |
482 { |