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