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> { |