src/kernels/gaussian.rs

branch
dev
changeset 32
56c8adc32b09
parent 0
eb3c7813b67a
equal deleted inserted replaced
30:bd13c2ae3450 32:56c8adc32b09
15 LocalAnalysis, 15 LocalAnalysis,
16 GlobalAnalysis, 16 GlobalAnalysis,
17 Weighted, 17 Weighted,
18 Bounded, 18 Bounded,
19 }; 19 };
20 use alg_tools::mapping::Apply; 20 use alg_tools::mapping::{Apply, Differentiable};
21 use alg_tools::maputil::array_init; 21 use alg_tools::maputil::array_init;
22 22
23 use crate::types::Lipschitz;
23 use crate::fourier::Fourier; 24 use crate::fourier::Fourier;
24 use super::base::*; 25 use super::base::*;
25 use super::ball_indicator::CubeIndicator; 26 use super::ball_indicator::CubeIndicator;
26 27
27 /// Storage presentation of the the anisotropic gaussian kernel of `variance` $σ^2$. 28 /// Storage presentation of the the anisotropic gaussian kernel of `variance` $σ^2$.
73 } 74 }
74 75
75 impl<S, const N : usize> Apply<Loc<S::Type, N>> for Gaussian<S, N> 76 impl<S, const N : usize> Apply<Loc<S::Type, N>> for Gaussian<S, N>
76 where S : Constant { 77 where S : Constant {
77 type Output = S::Type; 78 type Output = S::Type;
79 #[inline]
80 fn apply(&self, x : Loc<S::Type, N>) -> Self::Output {
81 self.apply(&x)
82 }
83 }
84
85 #[replace_float_literals(S::Type::cast_from(literal))]
86 impl<'a, S, const N : usize> Differentiable<&'a Loc<S::Type, N>> for Gaussian<S, N>
87 where S : Constant {
88 type Output = Loc<S::Type, N>;
89 #[inline]
90 fn differential(&self, x : &'a Loc<S::Type, N>) -> Self::Output {
91 x * (self.apply(x) / self.variance.value())
92 }
93 }
94
95 impl<S, const N : usize> Differentiable<Loc<S::Type, N>> for Gaussian<S, N>
96 where S : Constant {
97 type Output = Loc<S::Type, N>;
78 // This is not normalised to neither to have value 1 at zero or integral 1 98 // This is not normalised to neither to have value 1 at zero or integral 1
79 // (unless the cut-off ε=0). 99 // (unless the cut-off ε=0).
80 #[inline] 100 #[inline]
81 fn apply(&self, x : Loc<S::Type, N>) -> Self::Output { 101 fn differential(&self, x : Loc<S::Type, N>) -> Self::Output {
82 self.apply(&x) 102 x * (self.apply(&x) / self.variance.value())
83 } 103 }
84 } 104 }
85 105
106 #[replace_float_literals(S::Type::cast_from(literal))]
107 impl<S, const N : usize> Lipschitz<L2> for Gaussian<S, N>
108 where S : Constant {
109 type FloatType = S::Type;
110 fn lipschitz_factor(&self, L2 : L2) -> Option<Self::FloatType> {
111 // f(x)=f_1(‖x‖_2/σ) * √(2π) / √(2πσ)^N, where f_1 is one-dimensional Gaussian with
112 // variance 1. The Lipschitz factor of f_1 is e^{-1/2}/√(2π), see, e.g.,
113 // https://math.stackexchange.com/questions/3630967/is-the-gaussian-density-lipschitz-continuous
114 // Thus the Lipschitz factor we want is e^{-1/2} / (√(2πσ)^N * σ).
115 Some((-0.5).exp() / (self.scale() * self.variance.value().sqrt()))
116 }
117 }
86 118
87 #[replace_float_literals(S::Type::cast_from(literal))] 119 #[replace_float_literals(S::Type::cast_from(literal))]
88 impl<'a, S, const N : usize> Gaussian<S, N> 120 impl<'a, S, const N : usize> Gaussian<S, N>
89 where S : Constant { 121 where S : Constant {
90 122
167 /// where $a>0$ and $f$ is a gaussian kernel on $ℝ^n$. 199 /// where $a>0$ and $f$ is a gaussian kernel on $ℝ^n$.
168 pub type BasicCutGaussian<C, S, const N : usize> = SupportProductFirst<CubeIndicator<C, N>, 200 pub type BasicCutGaussian<C, S, const N : usize> = SupportProductFirst<CubeIndicator<C, N>,
169 Gaussian<S, N>>; 201 Gaussian<S, N>>;
170 202
171 203
172 /// This implements $χ\_{[-b, b]^n} \* (f χ\_{[-a, a]^n})$ 204 /// This implements $g := χ\_{[-b, b]^n} \* (f χ\_{[-a, a]^n})$ where $a,b>0$ and $f$ is
173 /// where $a,b>0$ and $f$ is a gaussian kernel on $ℝ^n$. 205 /// a gaussian kernel on $ℝ^n$. For an expression for $g$, see Lemma 3.9 in the manuscript.
174 #[replace_float_literals(F::cast_from(literal))] 206 #[replace_float_literals(F::cast_from(literal))]
175 impl<'a, F : Float, R, C, S, const N : usize> Apply<&'a Loc<F, N>> 207 impl<'a, F : Float, R, C, S, const N : usize> Apply<&'a Loc<F, N>>
176 for Convolution<CubeIndicator<R, N>, BasicCutGaussian<C, S, N>> 208 for Convolution<CubeIndicator<R, N>, BasicCutGaussian<C, S, N>>
177 where R : Constant<Type=F>, 209 where R : Constant<Type=F>,
178 C : Constant<Type=F>, 210 C : Constant<Type=F>,
222 fn apply(&self, y : Loc<F, N>) -> F { 254 fn apply(&self, y : Loc<F, N>) -> F {
223 self.apply(&y) 255 self.apply(&y)
224 } 256 }
225 } 257 }
226 258
259 /// This implements the differential of $g := χ\_{[-b, b]^n} \* (f χ\_{[-a, a]^n})$ where $a,b>0$
260 /// and $f$ is a gaussian kernel on $ℝ^n$. For an expression for the value of $g$, from which the
261 /// derivative readily arises (at points of differentiability), see Lemma 3.9 in the manuscript.
262 #[replace_float_literals(F::cast_from(literal))]
263 impl<'a, F : Float, R, C, S, const N : usize> Differentiable<&'a Loc<F, N>>
264 for Convolution<CubeIndicator<R, N>, BasicCutGaussian<C, S, N>>
265 where R : Constant<Type=F>,
266 C : Constant<Type=F>,
267 S : Constant<Type=F> {
268
269 type Output = Loc<F, N>;
270
271 #[inline]
272 fn differential(&self, y : &'a Loc<F, N>) -> Loc<F, N> {
273 let Convolution(ref ind,
274 SupportProductFirst(ref cut,
275 ref gaussian)) = self;
276 let a = cut.r.value();
277 let b = ind.r.value();
278 let σ = gaussian.variance.value().sqrt();
279 let π = F::PI;
280 let t = F::SQRT_2 * σ;
281 let c = σ * (8.0/π).sqrt();
282 let cd = (8.0).sqrt(); // σ * (8.0/π).sqrt() / t * (√2/π)
283
284 // Calculate the values for all component functions of the
285 // product. This is just the loop from apply above.
286 let unscaled_vs = y.map(|x| {
287 let c1 = -(a.min(b + x)); //(-a).max(-x-b);
288 let c2 = a.min(b - x);
289 if c1 >= c2 {
290 0.0
291 } else {
292 let e1 = F::cast_from(erf((c1 / t).as_()));
293 let e2 = F::cast_from(erf((c2 / t).as_()));
294 debug_assert!(e2 >= e1);
295 c * (e2 - e1)
296 }
297 });
298 // This computes the gradient for each coordinate
299 product_differential(y, &unscaled_vs, |x| {
300 let c1 = -(a.min(b + x)); //(-a).max(-x-b);
301 let c2 = a.min(b - x);
302 if c1 >= c2 {
303 0.0
304 } else {
305 // erf'(z) = (2/√π)*exp(-z^2), and we get extra factor -1/√(2*σ) = -1/t
306 // from the chain rule
307 let de1 = (-(c1/t).powi(2)).exp();
308 let de2 = (-(c2/t).powi(2)).exp();
309 cd * (de1 - de2)
310 }
311 }) / gaussian.scale()
312 }
313 }
314
315 impl<F : Float, R, C, S, const N : usize> Differentiable<Loc<F, N>>
316 for Convolution<CubeIndicator<R, N>, BasicCutGaussian<C, S, N>>
317 where R : Constant<Type=F>,
318 C : Constant<Type=F>,
319 S : Constant<Type=F> {
320
321 type Output = Loc<F, N>;
322
323 #[inline]
324 fn differential(&self, y : Loc<F, N>) -> Loc<F, N> {
325 self.differential(&y)
326 }
327 }
328
329 #[replace_float_literals(F::cast_from(literal))]
330 impl<'a, F : Float, R, C, S, const N : usize> Lipschitz<L2>
331 for Convolution<CubeIndicator<R, N>, BasicCutGaussian<C, S, N>>
332 where R : Constant<Type=F>,
333 C : Constant<Type=F>,
334 S : Constant<Type=F> {
335 type FloatType = F;
336
337 fn lipschitz_factor(&self, L2 : L2) -> Option<F> {
338 todo!("This requirement some error function work.")
339 }
340 }
341
227 impl<F : Float, R, C, S, const N : usize> 342 impl<F : Float, R, C, S, const N : usize>
228 Convolution<CubeIndicator<R, N>, BasicCutGaussian<C, S, N>> 343 Convolution<CubeIndicator<R, N>, BasicCutGaussian<C, S, N>>
229 where R : Constant<Type=F>, 344 where R : Constant<Type=F>,
230 C : Constant<Type=F>, 345 C : Constant<Type=F>,
231 S : Constant<Type=F> { 346 S : Constant<Type=F> {

mercurial