| 1 |
|
| 2 //! Implementation of the indicator function of a ball with respect to various norms. |
1 //! Implementation of the indicator function of a ball with respect to various norms. |
| |
2 use super::base::*; |
| |
3 use crate::types::*; |
| |
4 use alg_tools::bisection_tree::{Bounds, Constant, GlobalAnalysis, LocalAnalysis, Support}; |
| |
5 use alg_tools::coefficients::factorial; |
| |
6 use alg_tools::euclidean::StaticEuclidean; |
| |
7 use alg_tools::instance::Instance; |
| |
8 use alg_tools::loc::Loc; |
| |
9 use alg_tools::mapping::{DifferentiableImpl, Differential, LipschitzDifferentiableImpl, Mapping}; |
| |
10 use alg_tools::maputil::array_init; |
| |
11 use alg_tools::norms::*; |
| |
12 use alg_tools::sets::Cube; |
| |
13 use anyhow::anyhow; |
| 3 use float_extras::f64::tgamma as gamma; |
14 use float_extras::f64::tgamma as gamma; |
| 4 use numeric_literals::replace_float_literals; |
15 use numeric_literals::replace_float_literals; |
| 5 use serde::Serialize; |
16 use serde::Serialize; |
| 6 use alg_tools::types::*; |
|
| 7 use alg_tools::norms::*; |
|
| 8 use alg_tools::loc::Loc; |
|
| 9 use alg_tools::sets::Cube; |
|
| 10 use alg_tools::bisection_tree::{ |
|
| 11 Support, |
|
| 12 Constant, |
|
| 13 Bounds, |
|
| 14 LocalAnalysis, |
|
| 15 GlobalAnalysis, |
|
| 16 }; |
|
| 17 use alg_tools::mapping::{ |
|
| 18 Mapping, |
|
| 19 Differential, |
|
| 20 DifferentiableImpl, |
|
| 21 }; |
|
| 22 use alg_tools::instance::Instance; |
|
| 23 use alg_tools::euclidean::StaticEuclidean; |
|
| 24 use alg_tools::maputil::array_init; |
|
| 25 use alg_tools::coefficients::factorial; |
|
| 26 use crate::types::*; |
|
| 27 use super::base::*; |
|
| 28 |
17 |
| 29 /// Representation of the indicator of the ball $𝔹_q = \\{ x ∈ ℝ^N \mid \\|x\\|\_q ≤ r \\}$, |
18 /// Representation of the indicator of the ball $𝔹_q = \\{ x ∈ ℝ^N \mid \\|x\\|\_q ≤ r \\}$, |
| 30 /// where $q$ is the `Exponent`, and $r$ is the radius [`Constant`] `C`. |
19 /// where $q$ is the `Exponent`, and $r$ is the radius [`Constant`] `C`. |
| 31 #[derive(Copy,Clone,Serialize,Debug,Eq,PartialEq)] |
20 #[derive(Copy, Clone, Serialize, Debug, Eq, PartialEq)] |
| 32 pub struct BallIndicator<C : Constant, Exponent : NormExponent, const N : usize> { |
21 pub struct BallIndicator<C: Constant, Exponent: NormExponent, const N: usize> { |
| 33 /// The radius of the ball. |
22 /// The radius of the ball. |
| 34 pub r : C, |
23 pub r: C, |
| 35 /// The exponent $q$ of the norm creating the ball |
24 /// The exponent $q$ of the norm creating the ball |
| 36 pub exponent : Exponent, |
25 pub exponent: Exponent, |
| 37 } |
26 } |
| 38 |
27 |
| 39 /// Alias for the representation of the indicator of the $∞$-norm-ball |
28 /// Alias for the representation of the indicator of the $∞$-norm-ball |
| 40 /// $𝔹_∞ = \\{ x ∈ ℝ^N \mid \\|x\\|\_∞ ≤ c \\}$. |
29 /// $𝔹_∞ = \\{ x ∈ ℝ^N \mid \\|x\\|\_∞ ≤ c \\}$. |
| 41 pub type CubeIndicator<C, const N : usize> = BallIndicator<C, Linfinity, N>; |
30 pub type CubeIndicator<C, const N: usize> = BallIndicator<C, Linfinity, N>; |
| 42 |
31 |
| 43 #[replace_float_literals(C::Type::cast_from(literal))] |
32 #[replace_float_literals(C::Type::cast_from(literal))] |
| 44 impl<'a, F : Float, C : Constant<Type=F>, Exponent : NormExponent, const N : usize> |
33 impl<'a, F: Float, C: Constant<Type = F>, Exponent: NormExponent, const N: usize> |
| 45 Mapping<Loc<C::Type, N>> |
34 Mapping<Loc<N, C::Type>> for BallIndicator<C, Exponent, N> |
| 46 for BallIndicator<C, Exponent, N> |
35 where |
| 47 where |
36 Loc<N, F>: Norm<Exponent, F>, |
| 48 Loc<F, N> : Norm<F, Exponent> |
|
| 49 { |
37 { |
| 50 type Codomain = C::Type; |
38 type Codomain = C::Type; |
| 51 |
39 |
| 52 #[inline] |
40 #[inline] |
| 53 fn apply<I : Instance<Loc<C::Type, N>>>(&self, x : I) -> Self::Codomain { |
41 fn apply<I: Instance<Loc<N, C::Type>>>(&self, x: I) -> Self::Codomain { |
| 54 let r = self.r.value(); |
42 let r = self.r.value(); |
| 55 let n = x.eval(|x| x.norm(self.exponent)); |
43 let n = x.eval(|x| x.norm(self.exponent)); |
| 56 if n <= r { |
44 if n <= r { |
| 57 1.0 |
45 1.0 |
| 58 } else { |
46 } else { |
| 59 0.0 |
47 0.0 |
| 60 } |
48 } |
| 61 } |
49 } |
| 62 } |
50 } |
| 63 |
51 |
| 64 impl<'a, F : Float, C : Constant<Type=F>, Exponent : NormExponent, const N : usize> |
52 impl<'a, F: Float, C: Constant<Type = F>, Exponent: NormExponent, const N: usize> |
| 65 DifferentiableImpl<Loc<C::Type, N>> |
53 DifferentiableImpl<Loc<N, C::Type>> for BallIndicator<C, Exponent, N> |
| 66 for BallIndicator<C, Exponent, N> |
54 where |
| 67 where |
55 C: Constant, |
| 68 C : Constant, |
56 Loc<N, F>: Norm<Exponent, F>, |
| 69 Loc<F, N> : Norm<F, Exponent> |
57 { |
| 70 { |
58 type Derivative = Loc<N, C::Type>; |
| 71 type Derivative = Loc<C::Type, N>; |
59 |
| 72 |
60 #[inline] |
| 73 #[inline] |
61 fn differential_impl<I: Instance<Loc<N, C::Type>>>(&self, _x: I) -> Self::Derivative { |
| 74 fn differential_impl<I : Instance<Loc<C::Type, N>>>(&self, _x : I) -> Self::Derivative { |
|
| 75 Self::Derivative::origin() |
62 Self::Derivative::origin() |
| 76 } |
63 } |
| 77 } |
64 } |
| 78 |
65 |
| 79 impl<F : Float, C : Constant<Type=F>, Exponent : NormExponent, const N : usize> |
66 impl<F: Float, C: Constant<Type = F>, Exponent: NormExponent, const N: usize> Lipschitz<L2> |
| 80 Lipschitz<L2> |
67 for BallIndicator<C, Exponent, N> |
| 81 for BallIndicator<C, Exponent, N> |
68 where |
| 82 where C : Constant, |
69 C: Constant, |
| 83 Loc<F, N> : Norm<F, Exponent> { |
70 Loc<N, F>: Norm<Exponent, F>, |
| |
71 { |
| 84 type FloatType = C::Type; |
72 type FloatType = C::Type; |
| 85 |
73 |
| 86 fn lipschitz_factor(&self, _l2 : L2) -> Option<C::Type> { |
74 fn lipschitz_factor(&self, _l2: L2) -> DynResult<C::Type> { |
| 87 None |
75 Err(anyhow!("Not a Lipschitz function")) |
| 88 } |
76 } |
| 89 } |
77 } |
| 90 |
78 |
| 91 impl<'b, F : Float, C : Constant<Type=F>, Exponent : NormExponent, const N : usize> |
79 impl<'b, F: Float, C: Constant<Type = F>, Exponent: NormExponent, const N: usize> |
| 92 Lipschitz<L2> |
80 LipschitzDifferentiableImpl<Loc<N, F>, L2> for BallIndicator<C, Exponent, N> |
| 93 for Differential<'b, Loc<F, N>, BallIndicator<C, Exponent, N>> |
81 where |
| 94 where C : Constant, |
82 C: Constant, |
| 95 Loc<F, N> : Norm<F, Exponent> { |
83 Loc<N, F>: Norm<Exponent, F>, |
| |
84 { |
| 96 type FloatType = C::Type; |
85 type FloatType = C::Type; |
| 97 |
86 |
| 98 fn lipschitz_factor(&self, _l2 : L2) -> Option<C::Type> { |
87 fn diff_lipschitz_factor(&self, _l2: L2) -> DynResult<C::Type> { |
| 99 None |
88 Err(anyhow!("Not a Lipschitz-differentiable function")) |
| 100 } |
89 } |
| 101 } |
90 } |
| 102 |
91 |
| 103 impl<'a, 'b, F : Float, C : Constant<Type=F>, Exponent : NormExponent, const N : usize> |
92 impl<'b, F: Float, C: Constant<Type = F>, Exponent: NormExponent, const N: usize> NormBounded<L2> |
| 104 Lipschitz<L2> |
93 for Differential<'b, Loc<N, F>, BallIndicator<C, Exponent, N>> |
| 105 for Differential<'b, Loc<F, N>, &'a BallIndicator<C, Exponent, N>> |
94 where |
| 106 where C : Constant, |
95 C: Constant, |
| 107 Loc<F, N> : Norm<F, Exponent> { |
96 Loc<N, F>: Norm<Exponent, F>, |
| |
97 { |
| 108 type FloatType = C::Type; |
98 type FloatType = C::Type; |
| 109 |
99 |
| 110 fn lipschitz_factor(&self, _l2 : L2) -> Option<C::Type> { |
100 fn norm_bound(&self, _l2: L2) -> C::Type { |
| 111 None |
101 F::INFINITY |
| 112 } |
102 } |
| 113 } |
103 } |
| 114 |
104 |
| 115 |
105 impl<'a, 'b, F: Float, C: Constant<Type = F>, Exponent: NormExponent, const N: usize> |
| 116 impl<'b, F : Float, C : Constant<Type=F>, Exponent : NormExponent, const N : usize> |
106 NormBounded<L2> for Differential<'b, Loc<N, F>, &'a BallIndicator<C, Exponent, N>> |
| 117 NormBounded<L2> |
107 where |
| 118 for Differential<'b, Loc<F, N>, BallIndicator<C, Exponent, N>> |
108 C: Constant, |
| 119 where C : Constant, |
109 Loc<N, F>: Norm<Exponent, F>, |
| 120 Loc<F, N> : Norm<F, Exponent> { |
110 { |
| 121 type FloatType = C::Type; |
111 type FloatType = C::Type; |
| 122 |
112 |
| 123 fn norm_bound(&self, _l2 : L2) -> C::Type { |
113 fn norm_bound(&self, _l2: L2) -> C::Type { |
| 124 F::INFINITY |
114 F::INFINITY |
| 125 } |
115 } |
| 126 } |
116 } |
| 127 |
117 |
| 128 impl<'a, 'b, F : Float, C : Constant<Type=F>, Exponent : NormExponent, const N : usize> |
118 impl<'a, F: Float, C: Constant<Type = F>, Exponent, const N: usize> Support<N, C::Type> |
| 129 NormBounded<L2> |
119 for BallIndicator<C, Exponent, N> |
| 130 for Differential<'b, Loc<F, N>, &'a BallIndicator<C, Exponent, N>> |
120 where |
| 131 where C : Constant, |
121 Exponent: NormExponent + Sync + Send + 'static, |
| 132 Loc<F, N> : Norm<F, Exponent> { |
122 Loc<N, F>: Norm<Exponent, F>, |
| 133 type FloatType = C::Type; |
123 Linfinity: Dominated<F, Exponent, Loc<N, F>>, |
| 134 |
124 { |
| 135 fn norm_bound(&self, _l2 : L2) -> C::Type { |
125 #[inline] |
| 136 F::INFINITY |
126 fn support_hint(&self) -> Cube<N, F> { |
| 137 } |
|
| 138 } |
|
| 139 |
|
| 140 |
|
| 141 impl<'a, F : Float, C : Constant<Type=F>, Exponent : NormExponent, const N : usize> |
|
| 142 Support<C::Type, N> |
|
| 143 for BallIndicator<C, Exponent, N> |
|
| 144 where Loc<F, N> : Norm<F, Exponent>, |
|
| 145 Linfinity : Dominated<F, Exponent, Loc<F, N>> { |
|
| 146 |
|
| 147 #[inline] |
|
| 148 fn support_hint(&self) -> Cube<F,N> { |
|
| 149 let r = Linfinity.from_norm(self.r.value(), self.exponent); |
127 let r = Linfinity.from_norm(self.r.value(), self.exponent); |
| 150 array_init(|| [-r, r]).into() |
128 array_init(|| [-r, r]).into() |
| 151 } |
129 } |
| 152 |
130 |
| 153 #[inline] |
131 #[inline] |
| 154 fn in_support(&self, x : &Loc<F,N>) -> bool { |
132 fn in_support(&self, x: &Loc<N, F>) -> bool { |
| 155 let r = Linfinity.from_norm(self.r.value(), self.exponent); |
133 let r = Linfinity.from_norm(self.r.value(), self.exponent); |
| 156 x.norm(self.exponent) <= r |
134 x.norm(self.exponent) <= r |
| 157 } |
135 } |
| 158 |
136 |
| 159 /// This can only really work in a reasonable fashion for N=1. |
137 /// This can only really work in a reasonable fashion for N=1. |
| 160 #[inline] |
138 #[inline] |
| 161 fn bisection_hint(&self, cube : &Cube<F, N>) -> [Option<F>; N] { |
139 fn bisection_hint(&self, cube: &Cube<N, F>) -> [Option<F>; N] { |
| 162 let r = Linfinity.from_norm(self.r.value(), self.exponent); |
140 let r = Linfinity.from_norm(self.r.value(), self.exponent); |
| 163 cube.map(|a, b| symmetric_interval_hint(r, a, b)) |
141 cube.map(|a, b| symmetric_interval_hint(r, a, b)) |
| 164 } |
142 } |
| 165 } |
143 } |
| 166 |
144 |
| 167 #[replace_float_literals(F::cast_from(literal))] |
145 #[replace_float_literals(F::cast_from(literal))] |
| 168 impl<'a, F : Float, C : Constant<Type=F>, Exponent : NormExponent, const N : usize> |
146 impl<'a, F: Float, C: Constant<Type = F>, Exponent: NormExponent, const N: usize> |
| 169 GlobalAnalysis<F, Bounds<F>> |
147 GlobalAnalysis<F, Bounds<F>> for BallIndicator<C, Exponent, N> |
| 170 for BallIndicator<C, Exponent, N> |
148 where |
| 171 where Loc<F, N> : Norm<F, Exponent> { |
149 Loc<N, F>: Norm<Exponent, F>, |
| |
150 { |
| 172 #[inline] |
151 #[inline] |
| 173 fn global_analysis(&self) -> Bounds<F> { |
152 fn global_analysis(&self) -> Bounds<F> { |
| 174 Bounds(0.0, 1.0) |
153 Bounds(0.0, 1.0) |
| 175 } |
154 } |
| 176 } |
155 } |
| 177 |
156 |
| 178 #[replace_float_literals(F::cast_from(literal))] |
157 #[replace_float_literals(F::cast_from(literal))] |
| 179 impl<'a, F : Float, C : Constant<Type=F>, Exponent : NormExponent, const N : usize> |
158 impl<'a, F: Float, C: Constant<Type = F>, Exponent: NormExponent, const N: usize> Norm<Linfinity, F> |
| 180 Norm<F, Linfinity> |
159 for BallIndicator<C, Exponent, N> |
| 181 for BallIndicator<C, Exponent, N> |
160 where |
| 182 where Loc<F, N> : Norm<F, Exponent> { |
161 Loc<N, F>: Norm<Exponent, F>, |
| 183 #[inline] |
162 { |
| 184 fn norm(&self, _ : Linfinity) -> F { |
163 #[inline] |
| |
164 fn norm(&self, _: Linfinity) -> F { |
| 185 1.0 |
165 1.0 |
| 186 } |
166 } |
| 187 } |
167 } |
| 188 |
168 |
| 189 #[replace_float_literals(F::cast_from(literal))] |
169 #[replace_float_literals(F::cast_from(literal))] |
| 190 impl<'a, F : Float, C : Constant<Type=F>, const N : usize> |
170 impl<'a, F: Float, C: Constant<Type = F>, const N: usize> Norm<L1, F> for BallIndicator<C, L1, N> { |
| 191 Norm<F, L1> |
171 #[inline] |
| 192 for BallIndicator<C, L1, N> { |
172 fn norm(&self, _: L1) -> F { |
| 193 #[inline] |
|
| 194 fn norm(&self, _ : L1) -> F { |
|
| 195 // Using https://en.wikipedia.org/wiki/Volume_of_an_n-ball#Balls_in_Lp_norms, |
173 // Using https://en.wikipedia.org/wiki/Volume_of_an_n-ball#Balls_in_Lp_norms, |
| 196 // we have V_N^1(r) = (2r)^N / N! |
174 // we have V_N^1(r) = (2r)^N / N! |
| 197 let r = self.r.value(); |
175 let r = self.r.value(); |
| 198 if N==1 { |
176 if N == 1 { |
| 199 2.0 * r |
177 2.0 * r |
| 200 } else if N==2 { |
178 } else if N == 2 { |
| 201 r*r |
179 r * r |
| 202 } else { |
180 } else { |
| 203 (2.0 * r).powi(N as i32) * F::cast_from(factorial(N)) |
181 (2.0 * r).powi(N as i32) * F::cast_from(factorial(N)) |
| 204 } |
182 } |
| 205 } |
183 } |
| 206 } |
184 } |
| 207 |
185 |
| 208 #[replace_float_literals(F::cast_from(literal))] |
186 #[replace_float_literals(F::cast_from(literal))] |
| 209 impl<'a, F : Float, C : Constant<Type=F>, const N : usize> |
187 impl<'a, F: Float, C: Constant<Type = F>, const N: usize> Norm<L1, F> for BallIndicator<C, L2, N> { |
| 210 Norm<F, L1> |
188 #[inline] |
| 211 for BallIndicator<C, L2, N> { |
189 fn norm(&self, _: L1) -> F { |
| 212 #[inline] |
|
| 213 fn norm(&self, _ : L1) -> F { |
|
| 214 // See https://en.wikipedia.org/wiki/Volume_of_an_n-ball#The_volume. |
190 // See https://en.wikipedia.org/wiki/Volume_of_an_n-ball#The_volume. |
| 215 let r = self.r.value(); |
191 let r = self.r.value(); |
| 216 let π = F::PI; |
192 let π = F::PI; |
| 217 if N==1 { |
193 if N == 1 { |
| 218 2.0 * r |
194 2.0 * r |
| 219 } else if N==2 { |
195 } else if N == 2 { |
| 220 π * (r * r) |
196 π * (r * r) |
| 221 } else { |
197 } else { |
| 222 let ndiv2 = F::cast_from(N) / 2.0; |
198 let ndiv2 = F::cast_from(N) / 2.0; |
| 223 let γ = F::cast_from(gamma((ndiv2 + 1.0).as_())); |
199 let γ = F::cast_from(gamma((ndiv2 + 1.0).as_())); |
| 224 π.powf(ndiv2) / γ * r.powi(N as i32) |
200 π.powf(ndiv2) / γ * r.powi(N as i32) |
| 225 } |
201 } |
| 226 } |
202 } |
| 227 } |
203 } |
| 228 |
204 |
| 229 #[replace_float_literals(F::cast_from(literal))] |
205 #[replace_float_literals(F::cast_from(literal))] |
| 230 impl<'a, F : Float, C : Constant<Type=F>, const N : usize> |
206 impl<'a, F: Float, C: Constant<Type = F>, const N: usize> Norm<L1, F> |
| 231 Norm<F, L1> |
207 for BallIndicator<C, Linfinity, N> |
| 232 for BallIndicator<C, Linfinity, N> { |
208 { |
| 233 #[inline] |
209 #[inline] |
| 234 fn norm(&self, _ : L1) -> F { |
210 fn norm(&self, _: L1) -> F { |
| 235 let two_r = 2.0 * self.r.value(); |
211 let two_r = 2.0 * self.r.value(); |
| 236 two_r.powi(N as i32) |
212 two_r.powi(N as i32) |
| 237 } |
213 } |
| 238 } |
214 } |
| 239 |
215 |
| 240 |
|
| 241 macro_rules! indicator_local_analysis { |
216 macro_rules! indicator_local_analysis { |
| 242 ($exponent:ident) => { |
217 ($exponent:ident) => { |
| 243 impl<'a, F : Float, C : Constant<Type=F>, const N : usize> |
218 impl<'a, F: Float, C: Constant<Type = F>, const N: usize> LocalAnalysis<F, Bounds<F>, N> |
| 244 LocalAnalysis<F, Bounds<F>, N> |
219 for BallIndicator<C, $exponent, N> |
| 245 for BallIndicator<C, $exponent, N> |
220 where |
| 246 where Loc<F, N> : Norm<F, $exponent>, |
221 Loc<N, F>: Norm<$exponent, F>, |
| 247 Linfinity : Dominated<F, $exponent, Loc<F, N>> { |
222 Linfinity: Dominated<F, $exponent, Loc<N, F>>, |
| |
223 { |
| 248 #[inline] |
224 #[inline] |
| 249 fn local_analysis(&self, cube : &Cube<F, N>) -> Bounds<F> { |
225 fn local_analysis(&self, cube: &Cube<N, F>) -> Bounds<F> { |
| 250 // The function is maximised/minimised where the 2-norm is minimised/maximised. |
226 // The function is maximised/minimised where the 2-norm is minimised/maximised. |
| 251 let lower = self.apply(cube.maxnorm_point()); |
227 let lower = self.apply(cube.maxnorm_point()); |
| 252 let upper = self.apply(cube.minnorm_point()); |
228 let upper = self.apply(cube.minnorm_point()); |
| 253 Bounds(lower, upper) |
229 Bounds(lower, upper) |
| 254 } |
230 } |
| 255 } |
231 } |
| 256 } |
232 }; |
| 257 } |
233 } |
| 258 |
234 |
| 259 indicator_local_analysis!(L1); |
235 indicator_local_analysis!(L1); |
| 260 indicator_local_analysis!(L2); |
236 indicator_local_analysis!(L2); |
| 261 indicator_local_analysis!(Linfinity); |
237 indicator_local_analysis!(Linfinity); |
| 262 |
238 |
| 263 |
239 #[replace_float_literals(F::cast_from(literal))] |
| 264 #[replace_float_literals(F::cast_from(literal))] |
240 impl<'a, F: Float, R, const N: usize> Mapping<Loc<N, F>> for AutoConvolution<CubeIndicator<R, N>> |
| 265 impl<'a, F : Float, R, const N : usize> Mapping<Loc<F, N>> |
241 where |
| 266 for AutoConvolution<CubeIndicator<R, N>> |
242 R: Constant<Type = F>, |
| 267 where R : Constant<Type=F> { |
243 { |
| 268 type Codomain = F; |
244 type Codomain = F; |
| 269 |
245 |
| 270 #[inline] |
246 #[inline] |
| 271 fn apply<I : Instance<Loc<F, N>>>(&self, y : I) -> F { |
247 fn apply<I: Instance<Loc<N, F>>>(&self, y: I) -> F { |
| 272 let two_r = 2.0 * self.0.r.value(); |
248 let two_r = 2.0 * self.0.r.value(); |
| 273 // This is just a product of one-dimensional versions |
249 // This is just a product of one-dimensional versions |
| 274 y.cow().iter().map(|&x| { |
250 y.decompose() |
| 275 0.0.max(two_r - x.abs()) |
251 .iter() |
| 276 }).product() |
252 .map(|&x| 0.0.max(two_r - x.abs())) |
| 277 } |
253 .product() |
| 278 } |
254 } |
| 279 |
255 } |
| 280 #[replace_float_literals(F::cast_from(literal))] |
256 |
| 281 impl<F : Float, R, const N : usize> Support<F, N> |
257 #[replace_float_literals(F::cast_from(literal))] |
| 282 for AutoConvolution<CubeIndicator<R, N>> |
258 impl<F: Float, R, const N: usize> Support<N, F> for AutoConvolution<CubeIndicator<R, N>> |
| 283 where R : Constant<Type=F> { |
259 where |
| 284 #[inline] |
260 R: Constant<Type = F>, |
| 285 fn support_hint(&self) -> Cube<F, N> { |
261 { |
| |
262 #[inline] |
| |
263 fn support_hint(&self) -> Cube<N, F> { |
| 286 let two_r = 2.0 * self.0.r.value(); |
264 let two_r = 2.0 * self.0.r.value(); |
| 287 array_init(|| [-two_r, two_r]).into() |
265 array_init(|| [-two_r, two_r]).into() |
| 288 } |
266 } |
| 289 |
267 |
| 290 #[inline] |
268 #[inline] |
| 291 fn in_support(&self, y : &Loc<F, N>) -> bool { |
269 fn in_support(&self, y: &Loc<N, F>) -> bool { |
| 292 let two_r = 2.0 * self.0.r.value(); |
270 let two_r = 2.0 * self.0.r.value(); |
| 293 y.iter().all(|x| x.abs() <= two_r) |
271 y.iter().all(|x| x.abs() <= two_r) |
| 294 } |
272 } |
| 295 |
273 |
| 296 #[inline] |
274 #[inline] |
| 297 fn bisection_hint(&self, cube : &Cube<F, N>) -> [Option<F>; N] { |
275 fn bisection_hint(&self, cube: &Cube<N, F>) -> [Option<F>; N] { |
| 298 let two_r = 2.0 * self.0.r.value(); |
276 let two_r = 2.0 * self.0.r.value(); |
| 299 cube.map(|c, d| symmetric_interval_hint(two_r, c, d)) |
277 cube.map(|c, d| symmetric_interval_hint(two_r, c, d)) |
| 300 } |
278 } |
| 301 } |
279 } |
| 302 |
280 |
| 303 #[replace_float_literals(F::cast_from(literal))] |
281 #[replace_float_literals(F::cast_from(literal))] |
| 304 impl<F : Float, R, const N : usize> GlobalAnalysis<F, Bounds<F>> |
282 impl<F: Float, R, const N: usize> GlobalAnalysis<F, Bounds<F>> |
| 305 for AutoConvolution<CubeIndicator<R, N>> |
283 for AutoConvolution<CubeIndicator<R, N>> |
| 306 where R : Constant<Type=F> { |
284 where |
| |
285 R: Constant<Type = F>, |
| |
286 { |
| 307 #[inline] |
287 #[inline] |
| 308 fn global_analysis(&self) -> Bounds<F> { |
288 fn global_analysis(&self) -> Bounds<F> { |
| 309 Bounds(0.0, self.apply(Loc::ORIGIN)) |
289 Bounds(0.0, self.apply(Loc::ORIGIN)) |
| 310 } |
290 } |
| 311 } |
291 } |
| 312 |
292 |
| 313 impl<F : Float, R, const N : usize> LocalAnalysis<F, Bounds<F>, N> |
293 impl<F: Float, R, const N: usize> LocalAnalysis<F, Bounds<F>, N> |
| 314 for AutoConvolution<CubeIndicator<R, N>> |
294 for AutoConvolution<CubeIndicator<R, N>> |
| 315 where R : Constant<Type=F> { |
295 where |
| 316 #[inline] |
296 R: Constant<Type = F>, |
| 317 fn local_analysis(&self, cube : &Cube<F, N>) -> Bounds<F> { |
297 { |
| |
298 #[inline] |
| |
299 fn local_analysis(&self, cube: &Cube<N, F>) -> Bounds<F> { |
| 318 // The function is maximised/minimised where the absolute value is minimised/maximised. |
300 // The function is maximised/minimised where the absolute value is minimised/maximised. |
| 319 let lower = self.apply(cube.maxnorm_point()); |
301 let lower = self.apply(cube.maxnorm_point()); |
| 320 let upper = self.apply(cube.minnorm_point()); |
302 let upper = self.apply(cube.minnorm_point()); |
| 321 Bounds(lower, upper) |
303 Bounds(lower, upper) |
| 322 } |
304 } |