src/fb.rs

changeset 89
8d1c959432c8
parent 84
edb5de5d5bd6
child 91
47d495348e38
equal deleted inserted replaced
88:51dbb2cc25d9 89:8d1c959432c8
75 75
76 We solve this with either SSN or FB as determined by 76 We solve this with either SSN or FB as determined by
77 [`crate::subproblem::InnerSettings`] in [`InsertionConfig::inner`]. 77 [`crate::subproblem::InnerSettings`] in [`InsertionConfig::inner`].
78 */ 78 */
79 79
80 use crate::domain::{AdmissibleDomain, FullSpace};
80 use crate::measures::merging::SpikeMerging; 81 use crate::measures::merging::SpikeMerging;
81 use crate::measures::{DiscreteMeasure, RNDM}; 82 use crate::measures::{DiscreteMeasure, RNDM};
82 use crate::plot::Plotter; 83 use crate::plot::Plotter;
83 pub use crate::prox_penalty::{InsertionConfig, ProxPenalty, StepLengthBound}; 84 pub use crate::prox_penalty::{InsertionConfig, ProxPenalty, StepLengthBound};
84 use crate::regularisation::RegTerm; 85 use crate::regularisation::RegTerm;
87 use alg_tools::instance::Instance; 88 use alg_tools::instance::Instance;
88 use alg_tools::iterate::AlgIteratorFactory; 89 use alg_tools::iterate::AlgIteratorFactory;
89 use alg_tools::mapping::DifferentiableMapping; 90 use alg_tools::mapping::DifferentiableMapping;
90 use alg_tools::nalgebra_support::ToNalgebraRealField; 91 use alg_tools::nalgebra_support::ToNalgebraRealField;
91 use colored::Colorize; 92 use colored::Colorize;
93 use measures::DeltaMeasure;
92 use numeric_literals::replace_float_literals; 94 use numeric_literals::replace_float_literals;
93 use serde::{Deserialize, Serialize}; 95 use serde::{Deserialize, Serialize};
94 96
95 /// Settings for [`pointsource_fb_reg`]. 97 /// Settings for [`pointsource_fb_reg`].
96 #[derive(Clone, Copy, Eq, PartialEq, Serialize, Deserialize, Debug)] 98 #[derive(Clone, Copy, Eq, PartialEq, Serialize, Deserialize, Debug)]
144 /// 146 ///
145 /// For details on the mathematical formulation, see the [module level](self) documentation. 147 /// For details on the mathematical formulation, see the [module level](self) documentation.
146 /// 148 ///
147 /// Returns the final iterate. 149 /// Returns the final iterate.
148 #[replace_float_literals(F::cast_from(literal))] 150 #[replace_float_literals(F::cast_from(literal))]
149 pub fn pointsource_fb_reg<F, I, Dat, Reg, P, Plot, const N: usize>( 151 pub fn pointsource_fb_dom<F, I, Dat, Reg, P, Plot, const N: usize>(
150 f: &Dat, 152 f: &Dat,
151 reg: &Reg, 153 reg: &Reg,
152 prox_penalty: &P, 154 prox_penalty: &P,
153 fbconfig: &FBConfig<F>, 155 fbconfig: &FBConfig<F>,
154 iterator: I, 156 iterator: I,
155 mut plotter: Plot, 157 mut plotter: Plot,
156 μ0: Option<RNDM<N, F>>, 158 μ0: Option<RNDM<N, F>>,
159 domain: &mut impl AdmissibleDomain<Loc<N, F>>,
157 ) -> DynResult<RNDM<N, F>> 160 ) -> DynResult<RNDM<N, F>>
158 where 161 where
159 F: Float + ToNalgebraRealField, 162 F: Float + ToNalgebraRealField,
160 I: AlgIteratorFactory<IterInfo<F>>, 163 I: AlgIteratorFactory<IterInfo<F>>,
161 RNDM<N, F>: SpikeMerging<F>, 164 RNDM<N, F>: SpikeMerging<F>,
186 }; 189 };
187 let mut stats = IterInfo::new(); 190 let mut stats = IterInfo::new();
188 191
189 // Run the algorithm 192 // Run the algorithm
190 for state in iterator.iter_init(|| full_stats(&μ, ε, stats.clone())) { 193 for state in iterator.iter_init(|| full_stats(&μ, ε, stats.clone())) {
191 let maybe_μ_base = config.if_merge_now(&state, |_| μ.clone()); 194 let maybe_μ_base = config.if_merge_now_check(&state, || μ.clone());
192 let μ_base_len = μ.len(); 195 let μ_base_len = μ.len();
193 196
194 // Calculate smooth part of surrogate model. 197 // Calculate smooth part of surrogate model.
195 let mut τv = f.differential(&μ) * τ; 198 let mut τv = f.differential(&μ) * τ;
196 199
198 prox_penalty.insert_and_reweigh(&mut μ, &mut τv, τ, ε, config, &reg, &state, &mut stats)?; 201 prox_penalty.insert_and_reweigh(&mut μ, &mut τv, τ, ε, config, &reg, &state, &mut stats)?;
199 202
200 stats.inserted += μ.len() - μ_base_len; 203 stats.inserted += μ.len() - μ_base_len;
201 204
202 // Prune and possibly merge spikes 205 // Prune and possibly merge spikes
203 if let Some(μ_base) = maybe_μ_base { 206 let did_merge = if let Some(μ_base) = maybe_μ_base {
207 // Merge spikes.
208 // This crucially expects the merge routine to be stable with respect to spike locations,
209 // and not to performing any pruning. That is be to done below simultaneously for γ.
204 config.if_merge_now(&state, |ins| { 210 config.if_merge_now(&state, |ins| {
205 stats.merged += prox_penalty.merge_spikes( 211 stats.merged += prox_penalty.merge_spikes(
206 &mut μ, 212 &mut μ,
207 &mut τv, 213 &mut τv,
208 &μ_base, 214 &μ_base,
209 τ, 215 τ,
210 ε, 216 ε,
211 ins, 217 ins,
212 &reg, 218 &reg,
213 Some(|μ̃: &RNDM<N, F>| f.apply(μ̃) + reg.apply(μ̃)), 219 Some(|μ̃: &RNDM<N, F>| f.apply(μ̃) + reg.apply(μ̃)),
214 ) 220 );
215 }); 221 stats.pruned += prune_with_stats(&mut μ);
216 } 222
217 223 if config.random_insertions {
218 stats.pruned += prune_with_stats(&mut μ); 224 if let Some(x) = domain.random_point() {
219 225 μ += DeltaMeasure { x, α: 0.0 };
220 // Do extra weight optimisation step heuristic 226 stats.inserted += 1;
221 for _ in 0..config.extra_weight_optimisation_steps { 227 }
222 τv = f.differential(&μ) * τ; 228 }
223 prox_penalty.reweigh(&mut μ, &mut τv, τ, ε, config, &reg, &state, &mut stats)?; 229
224 } 230 // Do extra weight optimisation step heuristic
225 231 for _ in 1..config.extra_weight_optimisation_steps {
226 if config.extra_weight_optimisation_steps > 0 { 232 τv = f.differential(&μ) * τ;
233 prox_penalty
234 .reweigh(&mut μ, &mut τv, τ, ε, &config, &reg, &state, &mut stats)?;
235 }
236 Ok(())
237 })?
238 } else {
239 None
240 };
241
242 if did_merge.is_none() {
227 stats.pruned += prune_with_stats(&mut μ); 243 stats.pruned += prune_with_stats(&mut μ);
228 } 244 }
229 245
230 let iter = state.iteration(); 246 let iter = state.iteration();
231 stats.this_iters += 1; 247 stats.this_iters += 1;
240 ε = tolerance.update(ε, iter); 256 ε = tolerance.update(ε, iter);
241 } 257 }
242 258
243 //postprocess(μ_prev, config, f) 259 //postprocess(μ_prev, config, f)
244 postprocess(μ, config, |μ̃| f.apply(μ̃) + reg.apply(μ̃)) 260 postprocess(μ, config, |μ̃| f.apply(μ̃) + reg.apply(μ̃))
261 }
262
263 #[deprecated]
264 pub fn pointsource_fb_reg<F, I, Dat, Reg, P, Plot, const N: usize>(
265 f: &Dat,
266 reg: &Reg,
267 prox_penalty: &P,
268 fbconfig: &FBConfig<F>,
269 iterator: I,
270 plotter: Plot,
271 μ0: Option<RNDM<N, F>>,
272 ) -> DynResult<RNDM<N, F>>
273 where
274 F: Float + ToNalgebraRealField,
275 I: AlgIteratorFactory<IterInfo<F>>,
276 RNDM<N, F>: SpikeMerging<F>,
277 Dat: DifferentiableMapping<RNDM<N, F>, Codomain = F>,
278 Dat::DerivativeDomain: ClosedMul<F>,
279 Reg: RegTerm<Loc<N, F>, F>,
280 P: ProxPenalty<Loc<N, F>, Dat::DerivativeDomain, Reg, F> + StepLengthBound<F, Dat>,
281 Plot: Plotter<P::ReturnMapping, Dat::DerivativeDomain, RNDM<N, F>>,
282 {
283 pointsource_fb_dom(
284 f,
285 reg,
286 prox_penalty,
287 fbconfig,
288 iterator,
289 plotter,
290 μ0,
291 &mut FullSpace,
292 )
245 } 293 }
246 294
247 /// Iteratively solve the pointsource localisation problem using inertial forward-backward splitting. 295 /// Iteratively solve the pointsource localisation problem using inertial forward-backward splitting.
248 /// 296 ///
249 /// The settings in `config` have their [respective documentation](FBConfig). `opA` is the 297 /// The settings in `config` have their [respective documentation](FBConfig). `opA` is the
310 358
311 stats.inserted += μ.len() - μ_base_len; 359 stats.inserted += μ.len() - μ_base_len;
312 360
313 // (Do not) merge spikes. 361 // (Do not) merge spikes.
314 if !warned_merging { 362 if !warned_merging {
315 config.if_merge_now(&state, |_| { 363 config.if_merge_now_check(&state, || {
316 let err = format!("Merging not supported for μFISTA"); 364 let err = format!("Merging not supported for μFISTA");
317 println!("{}", err.red()); 365 println!("{}", err.red());
318 warned_merging = true; 366 warned_merging = true;
319 }); 367 });
320 } 368 }

mercurial