34 }; |
34 }; |
35 use crate::seminorms::DiscreteMeasureOp; |
35 use crate::seminorms::DiscreteMeasureOp; |
36 use crate::types::{ |
36 use crate::types::{ |
37 IterInfo, |
37 IterInfo, |
38 }; |
38 }; |
39 use crate::measures::merging::SpikeMergingMethod; |
|
40 use crate::regularisation::RegTerm; |
39 use crate::regularisation::RegTerm; |
41 use super::{ProxPenalty, FBGenericConfig}; |
40 use super::{ProxPenalty, FBGenericConfig}; |
42 |
41 |
43 #[replace_float_literals(F::cast_from(literal))] |
42 #[replace_float_literals(F::cast_from(literal))] |
44 impl<F, GA, BTA, S, Reg, 𝒟, G𝒟, K, const N : usize> |
43 impl<F, GA, BTA, S, Reg, 𝒟, G𝒟, K, const N : usize> |
72 ) -> (Option<BTFN<F, BothGenerators<GA, G𝒟>, BTA, N>>, bool) |
71 ) -> (Option<BTFN<F, BothGenerators<GA, G𝒟>, BTA, N>>, bool) |
73 where |
72 where |
74 I : AlgIterator |
73 I : AlgIterator |
75 { |
74 { |
76 |
75 |
77 // TODO: is this inefficient to do in every iteration? |
|
78 let op𝒟norm = self.opnorm_bound(Radon, Linfinity); |
76 let op𝒟norm = self.opnorm_bound(Radon, Linfinity); |
79 |
77 |
80 // Maximum insertion count and measure difference calculation depend on insertion style. |
78 // Maximum insertion count and measure difference calculation depend on insertion style. |
81 let (max_insertions, warn_insertions) = match (state.iteration(), config.bootstrap_insertions) { |
79 let (max_insertions, warn_insertions) = match (state.iteration(), config.bootstrap_insertions) { |
82 (i, Some((l, k))) if i <= l => (k, false), |
80 (i, Some((l, k))) if i <= l => (k, false), |
96 // from the beginning of the iteration are all contained in the immutable c and g. |
94 // from the beginning of the iteration are all contained in the immutable c and g. |
97 // TODO: observe negation of -τv after switch from minus_τv: finite-dimensional |
95 // TODO: observe negation of -τv after switch from minus_τv: finite-dimensional |
98 // problems have not yet been updated to sign change. |
96 // problems have not yet been updated to sign change. |
99 let à = self.findim_matrix(μ.iter_locations()); |
97 let à = self.findim_matrix(μ.iter_locations()); |
100 let g̃ = DVector::from_iterator(μ.len(), |
98 let g̃ = DVector::from_iterator(μ.len(), |
101 μ.iter_locations() |
99 μ.iter_locations() |
102 .map(|ζ| ω0.apply(ζ) - τv.apply(ζ)) |
100 .map(|ζ| ω0.apply(ζ) - τv.apply(ζ)) |
103 .map(F::to_nalgebra_mixed)); |
101 .map(F::to_nalgebra_mixed)); |
104 let mut x = μ.masses_dvector(); |
102 let mut x = μ.masses_dvector(); |
105 |
103 |
106 // The gradient of the forward component of the inner objective is C^*𝒟Cx - g̃. |
104 // The gradient of the forward component of the inner objective is C^*𝒟Cx - g̃. |
125 }; |
123 }; |
126 |
124 |
127 // If no merging heuristic is used, let's be more conservative about spike insertion, |
125 // If no merging heuristic is used, let's be more conservative about spike insertion, |
128 // and skip it after first round. If merging is done, being more greedy about spike |
126 // and skip it after first round. If merging is done, being more greedy about spike |
129 // insertion also seems to improve performance. |
127 // insertion also seems to improve performance. |
130 let skip_by_rough_check = if let SpikeMergingMethod::None = config.merging { |
128 let skip_by_rough_check = if config.merging.enabled { |
131 false |
129 false |
132 } else { |
130 } else { |
133 count > 0 |
131 count > 0 |
134 }; |
132 }; |
135 |
133 |
166 fn merge_spikes( |
164 fn merge_spikes( |
167 &self, |
165 &self, |
168 μ : &mut RNDM<F, N>, |
166 μ : &mut RNDM<F, N>, |
169 τv : &mut BTFN<F, GA, BTA, N>, |
167 τv : &mut BTFN<F, GA, BTA, N>, |
170 μ_base : &RNDM<F, N>, |
168 μ_base : &RNDM<F, N>, |
|
169 ν_delta: Option<&RNDM<F, N>>, |
171 τ : F, |
170 τ : F, |
172 ε : F, |
171 ε : F, |
173 config : &FBGenericConfig<F>, |
172 config : &FBGenericConfig<F>, |
174 reg : &Reg, |
173 reg : &Reg, |
|
174 fitness : Option<impl Fn(&RNDM<F, N>) -> F>, |
175 ) -> usize |
175 ) -> usize |
176 { |
176 { |
|
177 if config.fitness_merging { |
|
178 if let Some(f) = fitness { |
|
179 return μ.merge_spikes_fitness(config.merging, f, |&v| v) |
|
180 .1 |
|
181 } |
|
182 } |
177 μ.merge_spikes(config.merging, |μ_candidate| { |
183 μ.merge_spikes(config.merging, |μ_candidate| { |
178 let mut d = &*τv + self.preapply(μ_candidate.sub_matching(μ_base)); |
184 let mut d = &*τv + self.preapply(match ν_delta { |
|
185 None => μ_candidate.sub_matching(μ_base), |
|
186 Some(ν) => μ_candidate.sub_matching(μ_base) - ν, |
|
187 }); |
179 reg.verify_merge_candidate(&mut d, μ_candidate, τ, ε, config) |
188 reg.verify_merge_candidate(&mut d, μ_candidate, τ, ε, config) |
180 }) |
189 }) |
181 } |
190 } |
182 } |
191 } |