Tue, 31 Dec 2024 09:25:45 -0500
New version of sliding.
0 | 1 | |
2 | //! Implementation of the standard mollifier | |
3 | ||
4 | use rgsl::hypergeometric::hyperg_U; | |
35 | 5 | use float_extras::f64::tgamma as gamma; |
0 | 6 | use numeric_literals::replace_float_literals; |
7 | use serde::Serialize; | |
8 | use alg_tools::types::*; | |
9 | use alg_tools::euclidean::Euclidean; | |
10 | use alg_tools::norms::*; | |
11 | use alg_tools::loc::Loc; | |
12 | use alg_tools::sets::Cube; | |
13 | use alg_tools::bisection_tree::{ | |
14 | Support, | |
15 | Constant, | |
16 | Bounds, | |
17 | LocalAnalysis, | |
18 | GlobalAnalysis | |
19 | }; | |
35 | 20 | use alg_tools::mapping::{Mapping, Instance}; |
0 | 21 | use alg_tools::maputil::array_init; |
22 | ||
23 | /// Reresentation of the (unnormalised) standard mollifier. | |
24 | /// | |
25 | /// For the `width` parameter $ε>0$, this is | |
26 | /// <div>$$ | |
27 | /// f(x)=\begin{cases} | |
28 | /// e^{\frac{ε^2}{\|x\|_2^2-ε^2}}, & \|x\|_2 < ε, \\ | |
29 | /// 0, & \text{otherwise}. | |
30 | /// \end{cases} | |
31 | /// $$</div> | |
32 | #[derive(Copy,Clone,Serialize,Debug,Eq,PartialEq)] | |
33 | pub struct Mollifier<C : Constant, const N : usize> { | |
34 | /// The parameter $ε$ of the mollifier. | |
35 | pub width : C, | |
36 | } | |
37 | ||
38 | #[replace_float_literals(C::Type::cast_from(literal))] | |
35 | 39 | impl<C : Constant, const N : usize> Mapping<Loc<C::Type, N>> for Mollifier<C, N> { |
40 | type Codomain = C::Type; | |
41 | ||
0 | 42 | #[inline] |
35 | 43 | fn apply<I : Instance<Loc<C::Type, N>>>(&self, x : I) -> Self::Codomain { |
0 | 44 | let ε = self.width.value(); |
45 | let ε2 = ε*ε; | |
35 | 46 | let n2 = x.eval(|x| x.norm2_squared()); |
0 | 47 | if n2 < ε2 { |
48 | (n2 / (n2 - ε2)).exp() | |
49 | } else { | |
50 | 0.0 | |
51 | } | |
52 | } | |
53 | } | |
54 | ||
55 | ||
56 | impl<'a, C : Constant, const N : usize> Support<C::Type, N> for Mollifier<C, N> { | |
57 | #[inline] | |
58 | fn support_hint(&self) -> Cube<C::Type,N> { | |
59 | let ε = self.width.value(); | |
60 | array_init(|| [-ε, ε]).into() | |
61 | } | |
62 | ||
63 | #[inline] | |
64 | fn in_support(&self, x : &Loc<C::Type,N>) -> bool { | |
65 | x.norm2() < self.width.value() | |
66 | } | |
67 | ||
68 | /*fn fully_in_support(&self, _cube : &Cube<C::Type,N>) -> bool { | |
69 | todo!("Not implemented, but not used at the moment") | |
70 | }*/ | |
71 | } | |
72 | ||
73 | #[replace_float_literals(C::Type::cast_from(literal))] | |
74 | impl<'a, C : Constant, const N : usize> GlobalAnalysis<C::Type, Bounds<C::Type>> | |
75 | for Mollifier<C, N> { | |
76 | #[inline] | |
77 | fn global_analysis(&self) -> Bounds<C::Type> { | |
78 | // The function is maximised/minimised where the 2-norm is minimised/maximised. | |
79 | Bounds(0.0, 1.0) | |
80 | } | |
81 | } | |
82 | ||
83 | impl<'a, C : Constant, const N : usize> LocalAnalysis<C::Type, Bounds<C::Type>, N> | |
84 | for Mollifier<C, N> { | |
85 | #[inline] | |
86 | fn local_analysis(&self, cube : &Cube<C::Type, N>) -> Bounds<C::Type> { | |
87 | // The function is maximised/minimised where the 2-norm is minimised/maximised. | |
88 | let lower = self.apply(cube.maxnorm_point()); | |
89 | let upper = self.apply(cube.minnorm_point()); | |
90 | Bounds(lower, upper) | |
91 | } | |
92 | } | |
93 | ||
94 | /// Calculate integral of the standard mollifier of width 1 in $ℝ^n$. | |
95 | /// | |
96 | /// This is based on the formula from | |
97 | /// [https://math.stackexchange.com/questions/4359683/integral-of-the-usual-mollifier-function-finding-its-necessary-constant](). | |
98 | /// | |
99 | /// If `rescaled` is `true`, return the integral of the scaled mollifier that has value one at the | |
100 | /// origin. | |
101 | #[inline] | |
102 | pub fn mollifier_norm1(n_ : usize, rescaled : bool) -> f64 { | |
103 | assert!(n_ > 0); | |
104 | let n = n_ as f64; | |
105 | let q = 2.0; | |
106 | let p = 2.0; | |
107 | let base = (2.0*gamma(1.0 + 1.0/p)).powi(n_ as i32) | |
108 | /*/ gamma(1.0 + n / p) | |
109 | * gamma(1.0 + n / q)*/ | |
110 | * hyperg_U(1.0 + n / q, 2.0, 1.0); | |
111 | if rescaled { base } else { base / f64::E } | |
112 | } | |
113 | ||
114 | impl<'a, C : Constant, const N : usize> Norm<C::Type, L1> | |
115 | for Mollifier<C, N> { | |
116 | #[inline] | |
117 | fn norm(&self, _ : L1) -> C::Type { | |
118 | let ε = self.width.value(); | |
119 | C::Type::cast_from(mollifier_norm1(N, true)) * ε.powi(N as i32) | |
120 | } | |
121 | } | |
122 | ||
123 | #[replace_float_literals(C::Type::cast_from(literal))] | |
124 | impl<'a, C : Constant, const N : usize> Norm<C::Type, Linfinity> | |
125 | for Mollifier<C, N> { | |
126 | #[inline] | |
127 | fn norm(&self, _ : Linfinity) -> C::Type { | |
128 | 1.0 | |
129 | } | |
130 | } |