| 2 Regularisation terms |
2 Regularisation terms |
| 3 */ |
3 */ |
| 4 |
4 |
| 5 #[allow(unused_imports)] // Used by documentation. |
5 #[allow(unused_imports)] // Used by documentation. |
| 6 use crate::fb::pointsource_fb_reg; |
6 use crate::fb::pointsource_fb_reg; |
| 7 use crate::fb::FBGenericConfig; |
7 use crate::fb::InsertionConfig; |
| 8 use crate::measures::{DeltaMeasure, Radon, RNDM}; |
8 use crate::measures::{DeltaMeasure, DiscreteMeasure, Radon, RNDM}; |
| 9 #[allow(unused_imports)] // Used by documentation. |
9 #[allow(unused_imports)] // Used by documentation. |
| 10 use crate::sliding_fb::pointsource_sliding_fb_reg; |
10 use crate::sliding_fb::pointsource_sliding_fb_reg; |
| 11 use crate::types::*; |
11 use crate::types::*; |
| 12 use alg_tools::instance::Instance; |
12 use alg_tools::instance::{Instance, Space}; |
| 13 use alg_tools::linops::Mapping; |
13 use alg_tools::linops::Mapping; |
| 14 use alg_tools::loc::Loc; |
14 use alg_tools::loc::Loc; |
| 15 use alg_tools::norms::Norm; |
15 use alg_tools::norms::Norm; |
| 16 use numeric_literals::replace_float_literals; |
16 use numeric_literals::replace_float_literals; |
| 17 use serde::{Deserialize, Serialize}; |
17 use serde::{Deserialize, Serialize}; |
| 18 |
18 |
| 19 use crate::subproblem::{ |
19 use crate::subproblem::{ |
| 20 l1squared_nonneg::l1squared_nonneg, l1squared_unconstrained::l1squared_unconstrained, |
20 l1squared_nonneg::l1squared_nonneg, l1squared_unconstrained::l1squared_unconstrained, |
| 21 nonneg::quadratic_nonneg, unconstrained::quadratic_unconstrained, |
21 nonneg::quadratic_nonneg, unconstrained::quadratic_unconstrained, |
| 22 }; |
22 }; |
| 23 use alg_tools::bisection_tree::{ |
23 use alg_tools::bounds::{Bounds, MinMaxMapping}; |
| 24 BTSearch, Bounded, Bounds, LocalAnalysis, P2Minimise, SupportGenerator, BTFN, |
|
| 25 }; |
|
| 26 use alg_tools::iterate::AlgIteratorFactory; |
24 use alg_tools::iterate::AlgIteratorFactory; |
| 27 use alg_tools::nalgebra_support::ToNalgebraRealField; |
25 use alg_tools::nalgebra_support::ToNalgebraRealField; |
| 28 use nalgebra::{DMatrix, DVector}; |
26 use nalgebra::{DMatrix, DVector}; |
| 29 |
27 |
| 30 use std::cmp::Ordering::{Equal, Greater, Less}; |
28 use std::cmp::Ordering::{Equal, Greater, Less}; |
| 32 /// The regularisation term $α\\|μ\\|\_{ℳ(Ω)} + δ_{≥ 0}(μ)$ for [`pointsource_fb_reg`] and other |
30 /// The regularisation term $α\\|μ\\|\_{ℳ(Ω)} + δ_{≥ 0}(μ)$ for [`pointsource_fb_reg`] and other |
| 33 /// algorithms. |
31 /// algorithms. |
| 34 /// |
32 /// |
| 35 /// The only member of the struct is the regularisation parameter α. |
33 /// The only member of the struct is the regularisation parameter α. |
| 36 #[derive(Copy, Clone, Debug, Serialize, Deserialize)] |
34 #[derive(Copy, Clone, Debug, Serialize, Deserialize)] |
| 37 pub struct NonnegRadonRegTerm<F: Float>(pub F /* α */); |
35 pub struct NonnegRadonRegTerm<F: Float = f64>(pub F /* α */); |
| 38 |
36 |
| 39 impl<'a, F: Float> NonnegRadonRegTerm<F> { |
37 impl<'a, F: Float> NonnegRadonRegTerm<F> { |
| 40 /// Returns the regularisation parameter |
38 /// Returns the regularisation parameter |
| 41 pub fn α(&self) -> F { |
39 pub fn α(&self) -> F { |
| 42 let &NonnegRadonRegTerm(α) = self; |
40 let &NonnegRadonRegTerm(α) = self; |
| 43 α |
41 α |
| 44 } |
42 } |
| 45 } |
43 } |
| 46 |
44 |
| 47 impl<'a, F: Float, const N: usize> Mapping<RNDM<F, N>> for NonnegRadonRegTerm<F> { |
45 impl<'a, F: Float, const N: usize> Mapping<RNDM<N, F>> for NonnegRadonRegTerm<F> { |
| 48 type Codomain = F; |
46 type Codomain = F; |
| 49 |
47 |
| 50 fn apply<I>(&self, μ: I) -> F |
48 fn apply<I>(&self, μ: I) -> F |
| 51 where |
49 where |
| 52 I: Instance<RNDM<F, N>>, |
50 I: Instance<RNDM<N, F>>, |
| 53 { |
51 { |
| 54 self.α() * μ.eval(|x| x.norm(Radon)) |
52 self.α() * μ.eval(|x| x.norm(Radon)) |
| 55 } |
53 } |
| 56 } |
54 } |
| 57 |
55 |
| 58 /// The regularisation term $α\|μ\|_{ℳ(Ω)}$ for [`pointsource_fb_reg`]. |
56 /// The regularisation term $α\|μ\|_{ℳ(Ω)}$ for [`pointsource_fb_reg`]. |
| 59 /// |
57 /// |
| 60 /// The only member of the struct is the regularisation parameter α. |
58 /// The only member of the struct is the regularisation parameter α. |
| 61 #[derive(Copy, Clone, Debug, Serialize, Deserialize)] |
59 #[derive(Copy, Clone, Debug, Serialize, Deserialize)] |
| 62 pub struct RadonRegTerm<F: Float>(pub F /* α */); |
60 pub struct RadonRegTerm<F: Float = f64>(pub F /* α */); |
| 63 |
61 |
| 64 impl<'a, F: Float> RadonRegTerm<F> { |
62 impl<'a, F: Float> RadonRegTerm<F> { |
| 65 /// Returns the regularisation parameter |
63 /// Returns the regularisation parameter |
| 66 pub fn α(&self) -> F { |
64 pub fn α(&self) -> F { |
| 67 let &RadonRegTerm(α) = self; |
65 let &RadonRegTerm(α) = self; |
| 68 α |
66 α |
| 69 } |
67 } |
| 70 } |
68 } |
| 71 |
69 |
| 72 impl<'a, F: Float, const N: usize> Mapping<RNDM<F, N>> for RadonRegTerm<F> { |
70 impl<'a, F: Float, const N: usize> Mapping<RNDM<N, F>> for RadonRegTerm<F> { |
| 73 type Codomain = F; |
71 type Codomain = F; |
| 74 |
72 |
| 75 fn apply<I>(&self, μ: I) -> F |
73 fn apply<I>(&self, μ: I) -> F |
| 76 where |
74 where |
| 77 I: Instance<RNDM<F, N>>, |
75 I: Instance<RNDM<N, F>>, |
| 78 { |
76 { |
| 79 self.α() * μ.eval(|x| x.norm(Radon)) |
77 self.α() * μ.eval(|x| x.norm(Radon)) |
| 80 } |
78 } |
| 81 } |
79 } |
| 82 |
80 |
| 83 /// Regularisation term configuration |
81 /// Regularisation term configuration |
| 84 #[derive(Clone, Copy, Eq, PartialEq, Serialize, Deserialize, Debug)] |
82 #[derive(Clone, Copy, Eq, PartialEq, Serialize, Deserialize, Debug)] |
| 85 pub enum Regularisation<F: Float> { |
83 pub enum Regularisation<F: Float = f64> { |
| 86 /// $α \\|μ\\|\_{ℳ(Ω)}$ |
84 /// $α \\|μ\\|\_{ℳ(Ω)}$ |
| 87 Radon(F), |
85 Radon(F), |
| 88 /// $α\\|μ\\|\_{ℳ(Ω)} + δ_{≥ 0}(μ)$ |
86 /// $α\\|μ\\|\_{ℳ(Ω)} + δ_{≥ 0}(μ)$ |
| 89 NonnegRadon(F), |
87 NonnegRadon(F), |
| 90 } |
88 } |
| 91 |
89 |
| 92 impl<'a, F: Float, const N: usize> Mapping<RNDM<F, N>> for Regularisation<F> { |
90 impl<'a, F: Float, const N: usize> Mapping<RNDM<N, F>> for Regularisation<F> { |
| 93 type Codomain = F; |
91 type Codomain = F; |
| 94 |
92 |
| 95 fn apply<I>(&self, μ: I) -> F |
93 fn apply<I>(&self, μ: I) -> F |
| 96 where |
94 where |
| 97 I: Instance<RNDM<F, N>>, |
95 I: Instance<RNDM<N, F>>, |
| 98 { |
96 { |
| 99 match *self { |
97 match *self { |
| 100 Self::Radon(α) => RadonRegTerm(α).apply(μ), |
98 Self::Radon(α) => RadonRegTerm(α).apply(μ), |
| 101 Self::NonnegRadon(α) => NonnegRadonRegTerm(α).apply(μ), |
99 Self::NonnegRadon(α) => NonnegRadonRegTerm(α).apply(μ), |
| 102 } |
100 } |
| 103 } |
101 } |
| 104 } |
102 } |
| 105 |
103 |
| 106 /// Abstraction of regularisation terms. |
104 /// Abstraction of regularisation terms. |
| 107 pub trait RegTerm<F: Float + ToNalgebraRealField, const N: usize>: |
105 pub trait RegTerm<Domain, F = f64>: Mapping<DiscreteMeasure<Domain, F>, Codomain = F> |
| 108 Mapping<RNDM<F, N>, Codomain = F> |
106 where |
| |
107 Domain: Space + Clone, |
| |
108 F: Float + ToNalgebraRealField, |
| 109 { |
109 { |
| 110 /// Approximately solve the problem |
110 /// Approximately solve the problem |
| 111 /// <div>$$ |
111 /// <div>$$ |
| 112 /// \min_{x ∈ ℝ^n} \frac{1}{2} x^⊤Ax - g^⊤ x + τ G(x) |
112 /// \min_{x ∈ ℝ^n} \frac{1}{2} x^⊤Ax - g^⊤ x + τ G(x) |
| 113 /// $$</div> |
113 /// $$</div> |
| 152 /// regulariser. |
152 /// regulariser. |
| 153 /// |
153 /// |
| 154 /// Returns `None` if `d` is in bounds either based on the rough check, or a more precise check |
154 /// Returns `None` if `d` is in bounds either based on the rough check, or a more precise check |
| 155 /// terminating early. Otherwise returns a possibly violating point, the value of `d` there, |
155 /// terminating early. Otherwise returns a possibly violating point, the value of `d` there, |
| 156 /// and a boolean indicating whether the found point is in bounds. |
156 /// and a boolean indicating whether the found point is in bounds. |
| 157 fn find_tolerance_violation<G, BT>( |
157 fn find_tolerance_violation<M>( |
| 158 &self, |
158 &self, |
| 159 d: &mut BTFN<F, G, BT, N>, |
159 d: &mut M, |
| 160 τ: F, |
160 τ: F, |
| 161 ε: F, |
161 ε: F, |
| 162 skip_by_rough_check: bool, |
162 skip_by_rough_check: bool, |
| 163 config: &FBGenericConfig<F>, |
163 config: &InsertionConfig<F>, |
| 164 ) -> Option<(Loc<F, N>, F, bool)> |
164 ) -> Option<(Domain, F, bool)> |
| 165 where |
165 where |
| 166 BT: BTSearch<F, N, Agg = Bounds<F>>, |
166 M: MinMaxMapping<Domain, F>, |
| 167 G: SupportGenerator<F, N, Id = BT::Data>, |
|
| 168 G::SupportType: Mapping<Loc<F, N>, Codomain = F> + LocalAnalysis<F, Bounds<F>, N>, |
|
| 169 { |
167 { |
| 170 self.find_tolerance_violation_slack(d, τ, ε, skip_by_rough_check, config, F::ZERO) |
168 self.find_tolerance_violation_slack(d, τ, ε, skip_by_rough_check, config, F::ZERO) |
| 171 } |
169 } |
| 172 |
170 |
| 173 /// Find a point where `d` may violate the tolerance `ε`. |
171 /// Find a point where `d` may violate the tolerance `ε`. |
| 180 /// regulariser. |
178 /// regulariser. |
| 181 /// |
179 /// |
| 182 /// Returns `None` if `d` is in bounds either based on the rough check, or a more precise check |
180 /// Returns `None` if `d` is in bounds either based on the rough check, or a more precise check |
| 183 /// terminating early. Otherwise returns a possibly violating point, the value of `d` there, |
181 /// terminating early. Otherwise returns a possibly violating point, the value of `d` there, |
| 184 /// and a boolean indicating whether the found point is in bounds. |
182 /// and a boolean indicating whether the found point is in bounds. |
| 185 fn find_tolerance_violation_slack<G, BT>( |
183 fn find_tolerance_violation_slack<M>( |
| 186 &self, |
184 &self, |
| 187 d: &mut BTFN<F, G, BT, N>, |
185 d: &mut M, |
| 188 τ: F, |
186 τ: F, |
| 189 ε: F, |
187 ε: F, |
| 190 skip_by_rough_check: bool, |
188 skip_by_rough_check: bool, |
| 191 config: &FBGenericConfig<F>, |
189 config: &InsertionConfig<F>, |
| 192 slack: F, |
190 slack: F, |
| 193 ) -> Option<(Loc<F, N>, F, bool)> |
191 ) -> Option<(Domain, F, bool)> |
| 194 where |
192 where |
| 195 BT: BTSearch<F, N, Agg = Bounds<F>>, |
193 M: MinMaxMapping<Domain, F>; |
| 196 G: SupportGenerator<F, N, Id = BT::Data>, |
|
| 197 G::SupportType: Mapping<Loc<F, N>, Codomain = F> + LocalAnalysis<F, Bounds<F>, N>; |
|
| 198 |
194 |
| 199 /// Verify that `d` is in bounds `ε` for a merge candidate `μ` |
195 /// Verify that `d` is in bounds `ε` for a merge candidate `μ` |
| 200 /// |
196 /// |
| 201 /// `ε` is the current main tolerance and `τ` a scaling factor for the regulariser. |
197 /// `ε` is the current main tolerance and `τ` a scaling factor for the regulariser. |
| 202 fn verify_merge_candidate<G, BT>( |
198 fn verify_merge_candidate<M>( |
| 203 &self, |
199 &self, |
| 204 d: &mut BTFN<F, G, BT, N>, |
200 d: &mut M, |
| 205 μ: &RNDM<F, N>, |
201 μ: &DiscreteMeasure<Domain, F>, |
| 206 τ: F, |
202 τ: F, |
| 207 ε: F, |
203 ε: F, |
| 208 config: &FBGenericConfig<F>, |
204 config: &InsertionConfig<F>, |
| 209 ) -> bool |
205 ) -> bool |
| 210 where |
206 where |
| 211 BT: BTSearch<F, N, Agg = Bounds<F>>, |
207 M: MinMaxMapping<Domain, F>; |
| 212 G: SupportGenerator<F, N, Id = BT::Data>, |
|
| 213 G::SupportType: Mapping<Loc<F, N>, Codomain = F> + LocalAnalysis<F, Bounds<F>, N>; |
|
| 214 |
208 |
| 215 /// Verify that `d` is in bounds `ε` for a merge candidate `μ` |
209 /// Verify that `d` is in bounds `ε` for a merge candidate `μ` |
| 216 /// |
210 /// |
| 217 /// This version is s used for Radon-norm squared proximal term in |
211 /// This version is s used for Radon-norm squared proximal term in |
| 218 /// [`crate::prox_penalty::radon_squared`]. |
212 /// [`crate::prox_penalty::radon_squared`]. |
| 219 /// The [measures][crate::measures::DiscreteMeasure] `μ` and `radon_μ` are supposed to have |
213 /// The [measures][crate::measures::DiscreteMeasure] `μ` and `radon_μ` are supposed to have |
| 220 /// same coordinates at same agreeing indices. |
214 /// same coordinates at same agreeing indices. |
| 221 /// |
215 /// |
| 222 /// `ε` is the current main tolerance and `τ` a scaling factor for the regulariser. |
216 /// `ε` is the current main tolerance and `τ` a scaling factor for the regulariser. |
| 223 fn verify_merge_candidate_radonsq<G, BT>( |
217 fn verify_merge_candidate_radonsq<M>( |
| 224 &self, |
218 &self, |
| 225 d: &mut BTFN<F, G, BT, N>, |
219 d: &mut M, |
| 226 μ: &RNDM<F, N>, |
220 μ: &DiscreteMeasure<Domain, F>, |
| 227 τ: F, |
221 τ: F, |
| 228 ε: F, |
222 ε: F, |
| 229 config: &FBGenericConfig<F>, |
223 config: &InsertionConfig<F>, |
| 230 radon_μ: &RNDM<F, N>, |
224 radon_μ: &DiscreteMeasure<Domain, F>, |
| 231 ) -> bool |
225 ) -> bool |
| 232 where |
226 where |
| 233 BT: BTSearch<F, N, Agg = Bounds<F>>, |
227 M: MinMaxMapping<Domain, F>; |
| 234 G: SupportGenerator<F, N, Id = BT::Data>, |
|
| 235 G::SupportType: Mapping<Loc<F, N>, Codomain = F> + LocalAnalysis<F, Bounds<F>, N>; |
|
| 236 |
228 |
| 237 /// TODO: document this |
229 /// TODO: document this |
| 238 fn target_bounds(&self, τ: F, ε: F) -> Option<Bounds<F>>; |
230 fn target_bounds(&self, τ: F, ε: F) -> Option<Bounds<F>>; |
| 239 |
231 |
| 240 /// Returns a scaling factor for the tolerance sequence. |
232 /// Returns a scaling factor for the tolerance sequence. |
| 242 /// Typically this is the regularisation parameter. |
234 /// Typically this is the regularisation parameter. |
| 243 fn tolerance_scaling(&self) -> F; |
235 fn tolerance_scaling(&self) -> F; |
| 244 } |
236 } |
| 245 |
237 |
| 246 /// Abstraction of regularisation terms for [`pointsource_sliding_fb_reg`]. |
238 /// Abstraction of regularisation terms for [`pointsource_sliding_fb_reg`]. |
| 247 pub trait SlidingRegTerm<F: Float + ToNalgebraRealField, const N: usize>: RegTerm<F, N> { |
239 pub trait SlidingRegTerm<Domain, F = f64>: RegTerm<Domain, F> |
| |
240 where |
| |
241 Domain: Space + Clone, |
| |
242 F: Float + ToNalgebraRealField, |
| |
243 { |
| 248 /// Calculate $τ[w(z) - w(y)]$ for some w in the subdifferential of the regularisation |
244 /// Calculate $τ[w(z) - w(y)]$ for some w in the subdifferential of the regularisation |
| 249 /// term, such that $-ε ≤ τw - d ≤ ε$. |
245 /// term, such that $-ε ≤ τw - d ≤ ε$. |
| 250 fn goodness<G, BT>( |
246 fn goodness<M>( |
| 251 &self, |
247 &self, |
| 252 d: &mut BTFN<F, G, BT, N>, |
248 d: &mut M, |
| 253 μ: &RNDM<F, N>, |
249 μ: &DiscreteMeasure<Domain, F>, |
| 254 y: &Loc<F, N>, |
250 y: &Domain, |
| 255 z: &Loc<F, N>, |
251 z: &Domain, |
| 256 τ: F, |
252 τ: F, |
| 257 ε: F, |
253 ε: F, |
| 258 config: &FBGenericConfig<F>, |
254 config: &InsertionConfig<F>, |
| 259 ) -> F |
255 ) -> F |
| 260 where |
256 where |
| 261 BT: BTSearch<F, N, Agg = Bounds<F>>, |
257 M: MinMaxMapping<Domain, F>; |
| 262 G: SupportGenerator<F, N, Id = BT::Data>, |
|
| 263 G::SupportType: Mapping<Loc<F, N>, Codomain = F> + LocalAnalysis<F, Bounds<F>, N>; |
|
| 264 |
258 |
| 265 /// Convert bound on the regulariser to a bond on the Radon norm |
259 /// Convert bound on the regulariser to a bond on the Radon norm |
| 266 fn radon_norm_bound(&self, b: F) -> F; |
260 fn radon_norm_bound(&self, b: F) -> F; |
| 267 } |
261 } |
| 268 |
262 |
| 269 #[replace_float_literals(F::cast_from(literal))] |
263 #[replace_float_literals(F::cast_from(literal))] |
| 270 impl<F: Float + ToNalgebraRealField, const N: usize> RegTerm<F, N> for NonnegRadonRegTerm<F> |
264 impl<F: Float + ToNalgebraRealField, const N: usize> RegTerm<Loc<N, F>, F> |
| 271 where |
265 for NonnegRadonRegTerm<F> |
| 272 Cube<F, N>: P2Minimise<Loc<F, N>, F>, |
|
| 273 { |
266 { |
| 274 fn solve_findim( |
267 fn solve_findim( |
| 275 &self, |
268 &self, |
| 276 mA: &DMatrix<F::MixedType>, |
269 mA: &DMatrix<F::MixedType>, |
| 277 g: &DVector<F::MixedType>, |
270 g: &DVector<F::MixedType>, |
| 278 τ: F, |
271 τ: F, |
| 279 x: &mut DVector<F::MixedType>, |
272 x: &mut DVector<F::MixedType>, |
| 280 mA_normest: F, |
273 mA_normest: F, |
| 281 ε: F, |
274 ε: F, |
| 282 config: &FBGenericConfig<F>, |
275 config: &InsertionConfig<F>, |
| 283 ) -> usize { |
276 ) -> usize { |
| 284 let inner_tolerance = ε * config.inner.tolerance_mult; |
277 let inner_tolerance = ε * config.inner.tolerance_mult; |
| 285 let inner_it = config.inner.iterator_options.stop_target(inner_tolerance); |
278 let inner_it = config.inner.iterator_options.stop_target(inner_tolerance); |
| 286 quadratic_nonneg(mA, g, τ * self.α(), x, mA_normest, &config.inner, inner_it) |
279 quadratic_nonneg(mA, g, τ * self.α(), x, mA_normest, &config.inner, inner_it) |
| 287 } |
280 } |
| 291 y: &DVector<F::MixedType>, |
284 y: &DVector<F::MixedType>, |
| 292 g: &DVector<F::MixedType>, |
285 g: &DVector<F::MixedType>, |
| 293 τ: F, |
286 τ: F, |
| 294 x: &mut DVector<F::MixedType>, |
287 x: &mut DVector<F::MixedType>, |
| 295 ε: F, |
288 ε: F, |
| 296 config: &FBGenericConfig<F>, |
289 config: &InsertionConfig<F>, |
| 297 ) -> usize { |
290 ) -> usize { |
| 298 let inner_tolerance = ε * config.inner.tolerance_mult; |
291 let inner_tolerance = ε * config.inner.tolerance_mult; |
| 299 let inner_it = config.inner.iterator_options.stop_target(inner_tolerance); |
292 let inner_it = config.inner.iterator_options.stop_target(inner_tolerance); |
| 300 l1squared_nonneg(y, g, τ * self.α(), 1.0, x, &config.inner, inner_it) |
293 l1squared_nonneg(y, g, τ * self.α(), 1.0, x, &config.inner, inner_it) |
| 301 } |
294 } |
| 302 |
295 |
| 303 #[inline] |
296 #[inline] |
| 304 fn find_tolerance_violation_slack<G, BT>( |
297 fn find_tolerance_violation_slack<M>( |
| 305 &self, |
298 &self, |
| 306 d: &mut BTFN<F, G, BT, N>, |
299 d: &mut M, |
| 307 τ: F, |
300 τ: F, |
| 308 ε: F, |
301 ε: F, |
| 309 skip_by_rough_check: bool, |
302 skip_by_rough_check: bool, |
| 310 config: &FBGenericConfig<F>, |
303 config: &InsertionConfig<F>, |
| 311 slack: F, |
304 slack: F, |
| 312 ) -> Option<(Loc<F, N>, F, bool)> |
305 ) -> Option<(Loc<N, F>, F, bool)> |
| 313 where |
306 where |
| 314 BT: BTSearch<F, N, Agg = Bounds<F>>, |
307 M: MinMaxMapping<Loc<N, F>, F>, |
| 315 G: SupportGenerator<F, N, Id = BT::Data>, |
|
| 316 G::SupportType: Mapping<Loc<F, N>, Codomain = F> + LocalAnalysis<F, Bounds<F>, N>, |
|
| 317 { |
308 { |
| 318 let τα = τ * self.α(); |
309 let τα = τ * self.α(); |
| 319 let keep_above = -τα - slack - ε; |
310 let keep_above = -τα - slack - ε; |
| 320 let minimise_below = -τα - slack - ε * config.insertion_cutoff_factor; |
311 let minimise_below = -τα - slack - ε * config.insertion_cutoff_factor; |
| 321 let refinement_tolerance = ε * config.refinement.tolerance_mult; |
312 let refinement_tolerance = ε * config.refinement.tolerance_mult; |
| |
313 |
| |
314 // println!( |
| |
315 // "keep_above: {keep_above}, rough lower bound: {}, tolerance: {ε}, slack: {slack}, τα: {τα}", |
| |
316 // d.bounds().lower() |
| |
317 // ); |
| 322 |
318 |
| 323 // If preliminary check indicates that we are in bounds, and if it otherwise matches |
319 // If preliminary check indicates that we are in bounds, and if it otherwise matches |
| 324 // the insertion strategy, skip insertion. |
320 // the insertion strategy, skip insertion. |
| 325 if skip_by_rough_check && d.bounds().lower() >= keep_above { |
321 if skip_by_rough_check && d.bounds().lower() >= keep_above { |
| 326 None |
322 None |
| 327 } else { |
323 } else { |
| 328 // If the rough check didn't indicate no insertion needed, find minimising point. |
324 // If the rough check didn't indicate no insertion needed, find minimising point. |
| 329 d.minimise_below( |
325 let res = d.minimise_below( |
| 330 minimise_below, |
326 minimise_below, |
| 331 refinement_tolerance, |
327 refinement_tolerance, |
| 332 config.refinement.max_steps, |
328 config.refinement.max_steps, |
| 333 ) |
329 ); |
| 334 .map(|(ξ, v_ξ)| (ξ, v_ξ, v_ξ >= keep_above)) |
330 |
| |
331 res.map(|(ξ, v_ξ)| (ξ, v_ξ, v_ξ >= keep_above)) |
| 335 } |
332 } |
| 336 } |
333 } |
| 337 |
334 |
| 338 fn verify_merge_candidate<G, BT>( |
335 fn verify_merge_candidate<M>( |
| 339 &self, |
336 &self, |
| 340 d: &mut BTFN<F, G, BT, N>, |
337 d: &mut M, |
| 341 μ: &RNDM<F, N>, |
338 μ: &RNDM<N, F>, |
| 342 τ: F, |
339 τ: F, |
| 343 ε: F, |
340 ε: F, |
| 344 config: &FBGenericConfig<F>, |
341 config: &InsertionConfig<F>, |
| 345 ) -> bool |
342 ) -> bool |
| 346 where |
343 where |
| 347 BT: BTSearch<F, N, Agg = Bounds<F>>, |
344 M: MinMaxMapping<Loc<N, F>, F>, |
| 348 G: SupportGenerator<F, N, Id = BT::Data>, |
|
| 349 G::SupportType: Mapping<Loc<F, N>, Codomain = F> + LocalAnalysis<F, Bounds<F>, N>, |
|
| 350 { |
345 { |
| 351 let τα = τ * self.α(); |
346 let τα = τ * self.α(); |
| 352 let refinement_tolerance = ε * config.refinement.tolerance_mult; |
347 let refinement_tolerance = ε * config.refinement.tolerance_mult; |
| 353 let merge_tolerance = config.merge_tolerance_mult * ε; |
348 let merge_tolerance = config.merge_tolerance_mult * ε; |
| 354 let keep_above = -τα - merge_tolerance; |
349 let keep_above = -τα - merge_tolerance; |
| 365 refinement_tolerance, |
360 refinement_tolerance, |
| 366 config.refinement.max_steps, |
361 config.refinement.max_steps, |
| 367 )); |
362 )); |
| 368 } |
363 } |
| 369 |
364 |
| 370 fn verify_merge_candidate_radonsq<G, BT>( |
365 fn verify_merge_candidate_radonsq<M>( |
| 371 &self, |
366 &self, |
| 372 d: &mut BTFN<F, G, BT, N>, |
367 d: &mut M, |
| 373 μ: &RNDM<F, N>, |
368 μ: &RNDM<N, F>, |
| 374 τ: F, |
369 τ: F, |
| 375 ε: F, |
370 ε: F, |
| 376 config: &FBGenericConfig<F>, |
371 config: &InsertionConfig<F>, |
| 377 radon_μ: &RNDM<F, N>, |
372 radon_μ: &RNDM<N, F>, |
| 378 ) -> bool |
373 ) -> bool |
| 379 where |
374 where |
| 380 BT: BTSearch<F, N, Agg = Bounds<F>>, |
375 M: MinMaxMapping<Loc<N, F>, F>, |
| 381 G: SupportGenerator<F, N, Id = BT::Data>, |
|
| 382 G::SupportType: Mapping<Loc<F, N>, Codomain = F> + LocalAnalysis<F, Bounds<F>, N>, |
|
| 383 { |
376 { |
| 384 let τα = τ * self.α(); |
377 let τα = τ * self.α(); |
| 385 let refinement_tolerance = ε * config.refinement.tolerance_mult; |
378 let refinement_tolerance = ε * config.refinement.tolerance_mult; |
| 386 let merge_tolerance = config.merge_tolerance_mult * ε; |
379 let merge_tolerance = config.merge_tolerance_mult * ε; |
| 387 let slack = radon_μ.norm(Radon); |
380 let slack = radon_μ.norm(Radon); |
| 424 self.α() |
417 self.α() |
| 425 } |
418 } |
| 426 } |
419 } |
| 427 |
420 |
| 428 #[replace_float_literals(F::cast_from(literal))] |
421 #[replace_float_literals(F::cast_from(literal))] |
| 429 impl<F: Float + ToNalgebraRealField, const N: usize> SlidingRegTerm<F, N> for NonnegRadonRegTerm<F> |
422 impl<F: Float + ToNalgebraRealField, const N: usize> SlidingRegTerm<Loc<N, F>, F> |
| 430 where |
423 for NonnegRadonRegTerm<F> |
| 431 Cube<F, N>: P2Minimise<Loc<F, N>, F>, |
|
| 432 { |
424 { |
| 433 fn goodness<G, BT>( |
425 fn goodness<M>( |
| 434 &self, |
426 &self, |
| 435 d: &mut BTFN<F, G, BT, N>, |
427 d: &mut M, |
| 436 _μ: &RNDM<F, N>, |
428 _μ: &RNDM<N, F>, |
| 437 y: &Loc<F, N>, |
429 y: &Loc<N, F>, |
| 438 z: &Loc<F, N>, |
430 z: &Loc<N, F>, |
| 439 τ: F, |
431 τ: F, |
| 440 ε: F, |
432 ε: F, |
| 441 _config: &FBGenericConfig<F>, |
433 _config: &InsertionConfig<F>, |
| 442 ) -> F |
434 ) -> F |
| 443 where |
435 where |
| 444 BT: BTSearch<F, N, Agg = Bounds<F>>, |
436 M: MinMaxMapping<Loc<N, F>, F>, |
| 445 G: SupportGenerator<F, N, Id = BT::Data>, |
|
| 446 G::SupportType: Mapping<Loc<F, N>, Codomain = F> + LocalAnalysis<F, Bounds<F>, N>, |
|
| 447 { |
437 { |
| 448 let w = |x| 1.0.min((ε + d.apply(x)) / (τ * self.α())); |
438 let w = |x| 1.0.min((ε + d.apply(x)) / (τ * self.α())); |
| 449 w(z) - w(y) |
439 w(z) - w(y) |
| 450 } |
440 } |
| 451 |
441 |
| 453 b / self.α() |
443 b / self.α() |
| 454 } |
444 } |
| 455 } |
445 } |
| 456 |
446 |
| 457 #[replace_float_literals(F::cast_from(literal))] |
447 #[replace_float_literals(F::cast_from(literal))] |
| 458 impl<F: Float + ToNalgebraRealField, const N: usize> RegTerm<F, N> for RadonRegTerm<F> |
448 impl<F: Float + ToNalgebraRealField, const N: usize> RegTerm<Loc<N, F>, F> for RadonRegTerm<F> { |
| 459 where |
|
| 460 Cube<F, N>: P2Minimise<Loc<F, N>, F>, |
|
| 461 { |
|
| 462 fn solve_findim( |
449 fn solve_findim( |
| 463 &self, |
450 &self, |
| 464 mA: &DMatrix<F::MixedType>, |
451 mA: &DMatrix<F::MixedType>, |
| 465 g: &DVector<F::MixedType>, |
452 g: &DVector<F::MixedType>, |
| 466 τ: F, |
453 τ: F, |
| 467 x: &mut DVector<F::MixedType>, |
454 x: &mut DVector<F::MixedType>, |
| 468 mA_normest: F, |
455 mA_normest: F, |
| 469 ε: F, |
456 ε: F, |
| 470 config: &FBGenericConfig<F>, |
457 config: &InsertionConfig<F>, |
| 471 ) -> usize { |
458 ) -> usize { |
| 472 let inner_tolerance = ε * config.inner.tolerance_mult; |
459 let inner_tolerance = ε * config.inner.tolerance_mult; |
| 473 let inner_it = config.inner.iterator_options.stop_target(inner_tolerance); |
460 let inner_it = config.inner.iterator_options.stop_target(inner_tolerance); |
| 474 quadratic_unconstrained(mA, g, τ * self.α(), x, mA_normest, &config.inner, inner_it) |
461 quadratic_unconstrained(mA, g, τ * self.α(), x, mA_normest, &config.inner, inner_it) |
| 475 } |
462 } |
| 479 y: &DVector<F::MixedType>, |
466 y: &DVector<F::MixedType>, |
| 480 g: &DVector<F::MixedType>, |
467 g: &DVector<F::MixedType>, |
| 481 τ: F, |
468 τ: F, |
| 482 x: &mut DVector<F::MixedType>, |
469 x: &mut DVector<F::MixedType>, |
| 483 ε: F, |
470 ε: F, |
| 484 config: &FBGenericConfig<F>, |
471 config: &InsertionConfig<F>, |
| 485 ) -> usize { |
472 ) -> usize { |
| 486 let inner_tolerance = ε * config.inner.tolerance_mult; |
473 let inner_tolerance = ε * config.inner.tolerance_mult; |
| 487 let inner_it = config.inner.iterator_options.stop_target(inner_tolerance); |
474 let inner_it = config.inner.iterator_options.stop_target(inner_tolerance); |
| 488 l1squared_unconstrained(y, g, τ * self.α(), 1.0, x, &config.inner, inner_it) |
475 l1squared_unconstrained(y, g, τ * self.α(), 1.0, x, &config.inner, inner_it) |
| 489 } |
476 } |
| 490 |
477 |
| 491 fn find_tolerance_violation_slack<G, BT>( |
478 fn find_tolerance_violation_slack<M>( |
| 492 &self, |
479 &self, |
| 493 d: &mut BTFN<F, G, BT, N>, |
480 d: &mut M, |
| 494 τ: F, |
481 τ: F, |
| 495 ε: F, |
482 ε: F, |
| 496 skip_by_rough_check: bool, |
483 skip_by_rough_check: bool, |
| 497 config: &FBGenericConfig<F>, |
484 config: &InsertionConfig<F>, |
| 498 slack: F, |
485 slack: F, |
| 499 ) -> Option<(Loc<F, N>, F, bool)> |
486 ) -> Option<(Loc<N, F>, F, bool)> |
| 500 where |
487 where |
| 501 BT: BTSearch<F, N, Agg = Bounds<F>>, |
488 M: MinMaxMapping<Loc<N, F>, F>, |
| 502 G: SupportGenerator<F, N, Id = BT::Data>, |
|
| 503 G::SupportType: Mapping<Loc<F, N>, Codomain = F> + LocalAnalysis<F, Bounds<F>, N>, |
|
| 504 { |
489 { |
| 505 let τα = τ * self.α(); |
490 let τα = τ * self.α(); |
| 506 let keep_below = τα + slack + ε; |
491 let keep_below = τα + slack + ε; |
| 507 let keep_above = -(τα + slack) - ε; |
492 let keep_above = -(τα + slack) - ε; |
| 508 let maximise_above = τα + slack + ε * config.insertion_cutoff_factor; |
493 let maximise_above = τα + slack + ε * config.insertion_cutoff_factor; |
| 539 } |
524 } |
| 540 } |
525 } |
| 541 } |
526 } |
| 542 } |
527 } |
| 543 |
528 |
| 544 fn verify_merge_candidate<G, BT>( |
529 fn verify_merge_candidate<M>( |
| 545 &self, |
530 &self, |
| 546 d: &mut BTFN<F, G, BT, N>, |
531 d: &mut M, |
| 547 μ: &RNDM<F, N>, |
532 μ: &RNDM<N, F>, |
| 548 τ: F, |
533 τ: F, |
| 549 ε: F, |
534 ε: F, |
| 550 config: &FBGenericConfig<F>, |
535 config: &InsertionConfig<F>, |
| 551 ) -> bool |
536 ) -> bool |
| 552 where |
537 where |
| 553 BT: BTSearch<F, N, Agg = Bounds<F>>, |
538 M: MinMaxMapping<Loc<N, F>, F>, |
| 554 G: SupportGenerator<F, N, Id = BT::Data>, |
|
| 555 G::SupportType: Mapping<Loc<F, N>, Codomain = F> + LocalAnalysis<F, Bounds<F>, N>, |
|
| 556 { |
539 { |
| 557 let τα = τ * self.α(); |
540 let τα = τ * self.α(); |
| 558 let refinement_tolerance = ε * config.refinement.tolerance_mult; |
541 let refinement_tolerance = ε * config.refinement.tolerance_mult; |
| 559 let merge_tolerance = config.merge_tolerance_mult * ε; |
542 let merge_tolerance = config.merge_tolerance_mult * ε; |
| 560 let keep_below = τα + merge_tolerance; |
543 let keep_below = τα + merge_tolerance; |
| 583 refinement_tolerance, |
566 refinement_tolerance, |
| 584 config.refinement.max_steps, |
567 config.refinement.max_steps, |
| 585 )); |
568 )); |
| 586 } |
569 } |
| 587 |
570 |
| 588 fn verify_merge_candidate_radonsq<G, BT>( |
571 fn verify_merge_candidate_radonsq<M>( |
| 589 &self, |
572 &self, |
| 590 d: &mut BTFN<F, G, BT, N>, |
573 d: &mut M, |
| 591 μ: &RNDM<F, N>, |
574 μ: &RNDM<N, F>, |
| 592 τ: F, |
575 τ: F, |
| 593 ε: F, |
576 ε: F, |
| 594 config: &FBGenericConfig<F>, |
577 config: &InsertionConfig<F>, |
| 595 radon_μ: &RNDM<F, N>, |
578 radon_μ: &RNDM<N, F>, |
| 596 ) -> bool |
579 ) -> bool |
| 597 where |
580 where |
| 598 BT: BTSearch<F, N, Agg = Bounds<F>>, |
581 M: MinMaxMapping<Loc<N, F>, F>, |
| 599 G: SupportGenerator<F, N, Id = BT::Data>, |
|
| 600 G::SupportType: Mapping<Loc<F, N>, Codomain = F> + LocalAnalysis<F, Bounds<F>, N>, |
|
| 601 { |
582 { |
| 602 let τα = τ * self.α(); |
583 let τα = τ * self.α(); |
| 603 let refinement_tolerance = ε * config.refinement.tolerance_mult; |
584 let refinement_tolerance = ε * config.refinement.tolerance_mult; |
| 604 let merge_tolerance = config.merge_tolerance_mult * ε; |
585 let merge_tolerance = config.merge_tolerance_mult * ε; |
| 605 let slack = radon_μ.norm(Radon); |
586 let slack = radon_μ.norm(Radon); |
| 648 self.α() |
629 self.α() |
| 649 } |
630 } |
| 650 } |
631 } |
| 651 |
632 |
| 652 #[replace_float_literals(F::cast_from(literal))] |
633 #[replace_float_literals(F::cast_from(literal))] |
| 653 impl<F: Float + ToNalgebraRealField, const N: usize> SlidingRegTerm<F, N> for RadonRegTerm<F> |
634 impl<F: Float + ToNalgebraRealField, const N: usize> SlidingRegTerm<Loc<N, F>, F> |
| 654 where |
635 for RadonRegTerm<F> |
| 655 Cube<F, N>: P2Minimise<Loc<F, N>, F>, |
|
| 656 { |
636 { |
| 657 fn goodness<G, BT>( |
637 fn goodness<M>( |
| 658 &self, |
638 &self, |
| 659 d: &mut BTFN<F, G, BT, N>, |
639 d: &mut M, |
| 660 _μ: &RNDM<F, N>, |
640 _μ: &RNDM<N, F>, |
| 661 y: &Loc<F, N>, |
641 y: &Loc<N, F>, |
| 662 z: &Loc<F, N>, |
642 z: &Loc<N, F>, |
| 663 τ: F, |
643 τ: F, |
| 664 ε: F, |
644 ε: F, |
| 665 _config: &FBGenericConfig<F>, |
645 _config: &InsertionConfig<F>, |
| 666 ) -> F |
646 ) -> F |
| 667 where |
647 where |
| 668 BT: BTSearch<F, N, Agg = Bounds<F>>, |
648 M: MinMaxMapping<Loc<N, F>, F>, |
| 669 G: SupportGenerator<F, N, Id = BT::Data>, |
|
| 670 G::SupportType: Mapping<Loc<F, N>, Codomain = F> + LocalAnalysis<F, Bounds<F>, N>, |
|
| 671 { |
649 { |
| 672 let α = self.α(); |
650 let α = self.α(); |
| 673 let w = |x| { |
651 let w = |x| { |
| 674 let dx = d.apply(x); |
652 let dx = d.apply(x); |
| 675 ((-ε + dx) / (τ * α)).max(1.0.min(ε + dx) / (τ * α)) |
653 ((-ε + dx) / (τ * α)).max(1.0.min(ε + dx) / (τ * α)) |