1 /*! |
1 /*! |
2 Proximal penalty abstraction |
2 Proximal penalty abstraction |
3 */ |
3 */ |
4 |
4 |
|
5 use alg_tools::types::*; |
5 use numeric_literals::replace_float_literals; |
6 use numeric_literals::replace_float_literals; |
6 use alg_tools::types::*; |
7 use serde::{Deserialize, Serialize}; |
7 use serde::{Serialize, Deserialize}; |
|
8 |
8 |
|
9 use crate::measures::merging::SpikeMergingMethod; |
|
10 use crate::measures::RNDM; |
|
11 use crate::regularisation::RegTerm; |
|
12 use crate::subproblem::InnerSettings; |
|
13 use crate::tolerance::Tolerance; |
|
14 use crate::types::{IterInfo, RefinementSettings}; |
|
15 use alg_tools::iterate::{AlgIterator, AlgIteratorIteration}; |
9 use alg_tools::mapping::RealMapping; |
16 use alg_tools::mapping::RealMapping; |
10 use alg_tools::nalgebra_support::ToNalgebraRealField; |
17 use alg_tools::nalgebra_support::ToNalgebraRealField; |
11 use alg_tools::iterate::{ |
|
12 AlgIteratorIteration, |
|
13 AlgIterator, |
|
14 }; |
|
15 use crate::measures::RNDM; |
|
16 use crate::types::{ |
|
17 RefinementSettings, |
|
18 IterInfo, |
|
19 }; |
|
20 use crate::subproblem::InnerSettings; |
|
21 use crate::tolerance::Tolerance; |
|
22 use crate::measures::merging::SpikeMergingMethod; |
|
23 use crate::regularisation::RegTerm; |
|
24 |
18 |
|
19 pub mod radon_squared; |
25 pub mod wave; |
20 pub mod wave; |
26 pub mod radon_squared; |
|
27 pub use radon_squared::RadonSquared; |
21 pub use radon_squared::RadonSquared; |
28 |
22 |
29 /// Settings for the solution of the stepwise optimality condition. |
23 /// Settings for the solution of the stepwise optimality condition. |
30 #[derive(Clone, Copy, Eq, PartialEq, Serialize, Deserialize, Debug)] |
24 #[derive(Clone, Copy, Eq, PartialEq, Serialize, Deserialize, Debug)] |
31 #[serde(default)] |
25 #[serde(default)] |
32 pub struct FBGenericConfig<F : Float> { |
26 pub struct FBGenericConfig<F: Float> { |
33 /// Tolerance for point insertion. |
27 /// Tolerance for point insertion. |
34 pub tolerance : Tolerance<F>, |
28 pub tolerance: Tolerance<F>, |
35 |
29 |
36 /// Stop looking for predual maximum (where to isert a new point) below |
30 /// Stop looking for predual maximum (where to isert a new point) below |
37 /// `tolerance` multiplied by this factor. |
31 /// `tolerance` multiplied by this factor. |
38 /// |
32 /// |
39 /// Not used by [`super::radon_fb`]. |
33 /// Not used by [`crate::prox_penalty::radon_squared`]. |
40 pub insertion_cutoff_factor : F, |
34 pub insertion_cutoff_factor: F, |
41 |
35 |
42 /// Settings for branch and bound refinement when looking for predual maxima |
36 /// Settings for branch and bound refinement when looking for predual maxima |
43 pub refinement : RefinementSettings<F>, |
37 pub refinement: RefinementSettings<F>, |
44 |
38 |
45 /// Maximum insertions within each outer iteration |
39 /// Maximum insertions within each outer iteration |
46 /// |
40 /// |
47 /// Not used by [`super::radon_fb`]. |
41 /// Not used by [`crate::prox_penalty::radon_squared`]. |
48 pub max_insertions : usize, |
42 pub max_insertions: usize, |
49 |
43 |
50 /// Pair `(n, m)` for maximum insertions `m` on first `n` iterations. |
44 /// Pair `(n, m)` for maximum insertions `m` on first `n` iterations. |
51 /// |
45 /// |
52 /// Not used by [`super::radon_fb`]. |
46 /// Not used by [`crate::prox_penalty::radon_squared`]. |
53 pub bootstrap_insertions : Option<(usize, usize)>, |
47 pub bootstrap_insertions: Option<(usize, usize)>, |
54 |
48 |
55 /// Inner method settings |
49 /// Inner method settings |
56 pub inner : InnerSettings<F>, |
50 pub inner: InnerSettings<F>, |
57 |
51 |
58 /// Spike merging method |
52 /// Spike merging method |
59 pub merging : SpikeMergingMethod<F>, |
53 pub merging: SpikeMergingMethod<F>, |
60 |
54 |
61 /// Tolerance multiplier for merges |
55 /// Tolerance multiplier for merges |
62 pub merge_tolerance_mult : F, |
56 pub merge_tolerance_mult: F, |
63 |
57 |
64 /// Merge spikes after last step (even if merging not generally enabled) |
58 /// Merge spikes after last step (even if merging not generally enabled) |
65 pub final_merging : bool, |
59 pub final_merging: bool, |
66 |
60 |
67 /// Use fitness as merging criterion. Implies worse convergence guarantees. |
61 /// Use fitness as merging criterion. Implies worse convergence guarantees. |
68 pub fitness_merging : bool, |
62 pub fitness_merging: bool, |
69 |
63 |
70 /// Iterations between merging heuristic tries |
64 /// Iterations between merging heuristic tries |
71 pub merge_every : usize, |
65 pub merge_every: usize, |
72 |
|
73 // /// Save $μ$ for postprocessing optimisation |
66 // /// Save $μ$ for postprocessing optimisation |
74 // pub postprocessing : bool |
67 // pub postprocessing : bool |
75 } |
68 } |
76 |
69 |
77 #[replace_float_literals(F::cast_from(literal))] |
70 #[replace_float_literals(F::cast_from(literal))] |
78 impl<F : Float> Default for FBGenericConfig<F> { |
71 impl<F: Float> Default for FBGenericConfig<F> { |
79 fn default() -> Self { |
72 fn default() -> Self { |
80 FBGenericConfig { |
73 FBGenericConfig { |
81 tolerance : Default::default(), |
74 tolerance: Default::default(), |
82 insertion_cutoff_factor : 1.0, |
75 insertion_cutoff_factor: 1.0, |
83 refinement : Default::default(), |
76 refinement: Default::default(), |
84 max_insertions : 100, |
77 max_insertions: 100, |
85 //bootstrap_insertions : None, |
78 //bootstrap_insertions : None, |
86 bootstrap_insertions : Some((10, 1)), |
79 bootstrap_insertions: Some((10, 1)), |
87 inner : Default::default(), |
80 inner: Default::default(), |
88 merging : Default::default(), |
81 merging: Default::default(), |
89 final_merging : true, |
82 final_merging: true, |
90 fitness_merging : false, |
83 fitness_merging: false, |
91 merge_every : 10, |
84 merge_every: 10, |
92 merge_tolerance_mult : 2.0, |
85 merge_tolerance_mult: 2.0, |
93 // postprocessing : false, |
86 // postprocessing : false, |
94 } |
87 } |
95 } |
88 } |
96 } |
89 } |
97 |
90 |
98 impl<F : Float> FBGenericConfig<F> { |
91 impl<F: Float> FBGenericConfig<F> { |
99 /// Check if merging should be attempted this iteration |
92 /// Check if merging should be attempted this iteration |
100 pub fn merge_now<I : AlgIterator>(&self, state : &AlgIteratorIteration<I>) -> bool { |
93 pub fn merge_now<I: AlgIterator>(&self, state: &AlgIteratorIteration<I>) -> bool { |
101 self.merging.enabled && state.iteration() % self.merge_every == 0 |
94 self.merging.enabled && state.iteration() % self.merge_every == 0 |
102 } |
95 } |
103 |
96 |
104 /// Returns the final merging method |
97 /// Returns the final merging method |
105 pub fn final_merging_method(&self) -> SpikeMergingMethod<F> { |
98 pub fn final_merging_method(&self) -> SpikeMergingMethod<F> { |
106 SpikeMergingMethod{ enabled : self.final_merging, ..self.merging} |
99 SpikeMergingMethod { |
|
100 enabled: self.final_merging, |
|
101 ..self.merging |
|
102 } |
107 } |
103 } |
108 } |
104 } |
109 |
105 |
110 |
|
111 /// Trait for proximal penalties |
106 /// Trait for proximal penalties |
112 pub trait ProxPenalty<F, PreadjointCodomain, Reg, const N : usize> |
107 pub trait ProxPenalty<F, PreadjointCodomain, Reg, const N: usize> |
113 where |
108 where |
114 F : Float + ToNalgebraRealField, |
109 F: Float + ToNalgebraRealField, |
115 Reg : RegTerm<F, N>, |
110 Reg: RegTerm<F, N>, |
116 { |
111 { |
117 type ReturnMapping : RealMapping<F, N>; |
112 type ReturnMapping: RealMapping<F, N>; |
118 |
113 |
119 /// Insert new spikes into `μ` to approximately satisfy optimality conditions |
114 /// Insert new spikes into `μ` to approximately satisfy optimality conditions |
120 /// with the forward step term fixed to `τv`. |
115 /// with the forward step term fixed to `τv`. |
121 /// |
116 /// |
122 /// May return `τv + w` for `w` a subdifferential of the regularisation term `reg`, |
117 /// May return `τv + w` for `w` a subdifferential of the regularisation term `reg`, |
123 /// as well as an indication of whether the tolerance bounds `ε` are satisfied. |
118 /// as well as an indication of whether the tolerance bounds `ε` are satisfied. |
124 /// |
119 /// |
125 /// `μ_base + ν_delta` is the base point, where `μ` and `μ_base` are assumed to have the same |
120 /// `μ_base + ν_delta` is the base point, where `μ` and `μ_base` are assumed to have the same |
126 /// spike locations, while `ν_delta` may have different locations. |
121 /// spike locations, while `ν_delta` may have different locations. |
127 /// |
122 /// |
128 /// `τv` is mutable to allow [`alg_tools::bisection_tree::btfn::BTFN`] refinement. |
123 /// `τv` is mutable to allow [`alg_tools::bisection_tree::BTFN`] refinement. |
129 /// Actual values of `τv` are not supposed to be mutated. |
124 /// Actual values of `τv` are not supposed to be mutated. |
130 fn insert_and_reweigh<I>( |
125 fn insert_and_reweigh<I>( |
131 &self, |
126 &self, |
132 μ : &mut RNDM<F, N>, |
127 μ: &mut RNDM<F, N>, |
133 τv : &mut PreadjointCodomain, |
128 τv: &mut PreadjointCodomain, |
134 μ_base : &RNDM<F, N>, |
129 μ_base: &RNDM<F, N>, |
135 ν_delta: Option<&RNDM<F, N>>, |
130 ν_delta: Option<&RNDM<F, N>>, |
136 τ : F, |
131 τ: F, |
137 ε : F, |
132 ε: F, |
138 config : &FBGenericConfig<F>, |
133 config: &FBGenericConfig<F>, |
139 reg : &Reg, |
134 reg: &Reg, |
140 state : &AlgIteratorIteration<I>, |
135 state: &AlgIteratorIteration<I>, |
141 stats : &mut IterInfo<F, N>, |
136 stats: &mut IterInfo<F, N>, |
142 ) -> (Option<Self::ReturnMapping>, bool) |
137 ) -> (Option<Self::ReturnMapping>, bool) |
143 where |
138 where |
144 I : AlgIterator; |
139 I: AlgIterator; |
145 |
|
146 |
140 |
147 /// Merge spikes, if possible. |
141 /// Merge spikes, if possible. |
148 /// |
142 /// |
149 /// Either optimality condition merging or objective value (fitness) merging |
143 /// Either optimality condition merging or objective value (fitness) merging |
150 /// may be used, the latter only if `fitness` is provided and `config.fitness_merging` |
144 /// may be used, the latter only if `fitness` is provided and `config.fitness_merging` |
151 /// is set. |
145 /// is set. |
152 fn merge_spikes( |
146 fn merge_spikes( |
153 &self, |
147 &self, |
154 μ : &mut RNDM<F, N>, |
148 μ: &mut RNDM<F, N>, |
155 τv : &mut PreadjointCodomain, |
149 τv: &mut PreadjointCodomain, |
156 μ_base : &RNDM<F, N>, |
150 μ_base: &RNDM<F, N>, |
157 ν_delta: Option<&RNDM<F, N>>, |
151 ν_delta: Option<&RNDM<F, N>>, |
158 τ : F, |
152 τ: F, |
159 ε : F, |
153 ε: F, |
160 config : &FBGenericConfig<F>, |
154 config: &FBGenericConfig<F>, |
161 reg : &Reg, |
155 reg: &Reg, |
162 fitness : Option<impl Fn(&RNDM<F, N>) -> F>, |
156 fitness: Option<impl Fn(&RNDM<F, N>) -> F>, |
163 ) -> usize; |
157 ) -> usize; |
164 |
158 |
165 /// Merge spikes, if possible. |
159 /// Merge spikes, if possible. |
166 /// |
160 /// |
167 /// Unlike [`merge_spikes`], this variant only supports optimality condition based merging |
161 /// Unlike [`Self::merge_spikes`], this variant only supports optimality condition based merging |
168 #[inline] |
162 #[inline] |
169 fn merge_spikes_no_fitness( |
163 fn merge_spikes_no_fitness( |
170 &self, |
164 &self, |
171 μ : &mut RNDM<F, N>, |
165 μ: &mut RNDM<F, N>, |
172 τv : &mut PreadjointCodomain, |
166 τv: &mut PreadjointCodomain, |
173 μ_base : &RNDM<F, N>, |
167 μ_base: &RNDM<F, N>, |
174 ν_delta: Option<&RNDM<F, N>>, |
168 ν_delta: Option<&RNDM<F, N>>, |
175 τ : F, |
169 τ: F, |
176 ε : F, |
170 ε: F, |
177 config : &FBGenericConfig<F>, |
171 config: &FBGenericConfig<F>, |
178 reg : &Reg, |
172 reg: &Reg, |
179 ) -> usize { |
173 ) -> usize { |
180 /// This is a hack to create a `None` of same type as a `Some` |
174 /// This is a hack to create a `None` of same type as a `Some` |
181 // for the `impl Fn` parameter of `merge_spikes`. |
175 // for the `impl Fn` parameter of `merge_spikes`. |
182 #[inline] |
176 #[inline] |
183 fn into_none<T>(_ : Option<T>) -> Option<T>{ |
177 fn into_none<T>(_: Option<T>) -> Option<T> { |
184 None |
178 None |
185 } |
179 } |
186 self.merge_spikes(μ, τv, μ_base, ν_delta, τ, ε, config, reg, |
180 self.merge_spikes( |
187 into_none(Some(|_ : &RNDM<F, N>| F::ZERO))) |
181 μ, |
|
182 τv, |
|
183 μ_base, |
|
184 ν_delta, |
|
185 τ, |
|
186 ε, |
|
187 config, |
|
188 reg, |
|
189 into_none(Some(|_: &RNDM<F, N>| F::ZERO)), |
|
190 ) |
188 } |
191 } |
189 } |
192 } |