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 } |