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