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