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