src/forward_pdps.rs

changeset 89
8d1c959432c8
parent 84
edb5de5d5bd6
child 91
47d495348e38
equal deleted inserted replaced
88:51dbb2cc25d9 89:8d1c959432c8
1 /*! 1 /*!
2 Solver for the point source localisation problem using a 2 Solver for the point source localisation problem using a
3 primal-dual proximal splitting with a forward step. 3 primal-dual proximal splitting with a forward step.
4 */ 4 */
5 5
6 use crate::domain::{AdmissibleDomain, FullSpace};
6 use crate::fb::*; 7 use crate::fb::*;
7 use crate::measures::merging::SpikeMerging; 8 use crate::measures::merging::SpikeMerging;
8 use crate::measures::{DiscreteMeasure, RNDM}; 9 use crate::measures::{DiscreteMeasure, RNDM};
9 use crate::plot::Plotter; 10 use crate::plot::Plotter;
10 use crate::prox_penalty::{ProxPenalty, StepLengthBoundPair}; 11 use crate::prox_penalty::{ProxPenalty, StepLengthBoundPair};
18 use alg_tools::linops::{BoundedLinear, IdOp, SimplyAdjointable, ZeroOp, AXPY, GEMV}; 19 use alg_tools::linops::{BoundedLinear, IdOp, SimplyAdjointable, ZeroOp, AXPY, GEMV};
19 use alg_tools::mapping::{DifferentiableMapping, DifferentiableRealMapping, Instance}; 20 use alg_tools::mapping::{DifferentiableMapping, DifferentiableRealMapping, Instance};
20 use alg_tools::nalgebra_support::ToNalgebraRealField; 21 use alg_tools::nalgebra_support::ToNalgebraRealField;
21 use alg_tools::norms::L2; 22 use alg_tools::norms::L2;
22 use anyhow::ensure; 23 use anyhow::ensure;
24 use measures::DeltaMeasure;
23 use numeric_literals::replace_float_literals; 25 use numeric_literals::replace_float_literals;
24 use serde::{Deserialize, Serialize}; 26 use serde::{Deserialize, Serialize};
25 27
26 /// Settings for [`pointsource_forward_pdps_pair`]. 28 /// Settings for [`pointsource_forward_pdps_pair`].
27 #[derive(Clone, Copy, Eq, PartialEq, Serialize, Deserialize, Debug)] 29 #[derive(Clone, Copy, Eq, PartialEq, Serialize, Deserialize, Debug)]
83 /// part $[σ_p L_z + σ_pσ_d‖K_z‖^2] < 1$. Then with these cohices, we solve 85 /// part $[σ_p L_z + σ_pσ_d‖K_z‖^2] < 1$. Then with these cohices, we solve
84 /// $$ 86 /// $$
85 /// τ = τ_0 \frac{1 - σ_{p,0}}{(σ_d M (1-σ_p L_z) + (1 - σ_{p,0} L)}. 87 /// τ = τ_0 \frac{1 - σ_{p,0}}{(σ_d M (1-σ_p L_z) + (1 - σ_{p,0} L)}.
86 /// $$ 88 /// $$
87 #[replace_float_literals(F::cast_from(literal))] 89 #[replace_float_literals(F::cast_from(literal))]
88 pub fn pointsource_forward_pdps_pair< 90 pub fn pointsource_forward_pdps_pair_dom<
89 F, 91 F,
90 I, 92 I,
91 S, 93 S,
92 Dat, 94 Dat,
93 Reg, 95 Reg,
109 (μ0, mut z, mut y): (Option<RNDM<N, F>>, Z, Y), 111 (μ0, mut z, mut y): (Option<RNDM<N, F>>, Z, Y),
110 //opKμ : KOpM, 112 //opKμ : KOpM,
111 opKz: &KOpZ, 113 opKz: &KOpZ,
112 fnR: &R, 114 fnR: &R,
113 fnH: &H, 115 fnH: &H,
116 domain: &mut impl AdmissibleDomain<Loc<N, F>>,
114 ) -> DynResult<MeasureZ<F, Z, N>> 117 ) -> DynResult<MeasureZ<F, Z, N>>
115 where 118 where
116 F: Float + ToNalgebraRealField, 119 F: Float + ToNalgebraRealField,
117 I: AlgIteratorFactory<IterInfo<F>>, 120 I: AlgIteratorFactory<IterInfo<F>>,
118 Dat: DifferentiableMapping<MeasureZ<F, Z, N>, Codomain = F, DerivativeDomain = Pair<S, Z>>, 121 Dat: DifferentiableMapping<MeasureZ<F, Z, N>, Codomain = F, DerivativeDomain = Pair<S, Z>>,
235 stats.inserted += μ.len() - μ_base.len(); 238 stats.inserted += μ.len() - μ_base.len();
236 239
237 // Merge spikes. 240 // Merge spikes.
238 // This crucially expects the merge routine to be stable with respect to spike locations, 241 // This crucially expects the merge routine to be stable with respect to spike locations,
239 // and not to performing any pruning. That is be to done below simultaneously for γ. 242 // and not to performing any pruning. That is be to done below simultaneously for γ.
240 // Merge spikes. 243 let did_merge = config.insertion.if_merge_now(&state, |ins| {
241 // This crucially expects the merge routine to be stable with respect to spike locations,
242 // and not to performing any pruning. That is be to done below simultaneously for γ.
243 config.insertion.if_merge_now(&state, |ins| {
244 stats.merged += prox_penalty.merge_spikes( 244 stats.merged += prox_penalty.merge_spikes(
245 &mut μ, 245 &mut μ,
246 &mut τv, 246 &mut τv,
247 &μ_base, 247 &μ_base,
248 τ, 248 τ,
249 ε, 249 ε,
250 ins, 250 ins,
251 &reg, 251 &reg,
252 Some(|μ̃: &RNDM<N, F>| f.apply(Pair(μ̃, &z))+ reg.apply(μ̃)), 252 Some(|μ̃: &RNDM<N, F>| f.apply(Pair(μ̃, &z)) + reg.apply(μ̃)),
253 ); 253 );
254 }); 254 stats.pruned += prune_with_stats(&mut μ);
255 255
256 // Prune spikes with zero weight. 256 if config.insertion.random_insertions {
257 stats.pruned += prune_with_stats(&mut μ); 257 if let Some(x) = domain.random_point() {
258 258 μ += DeltaMeasure { x, α: 0.0 };
259 for _ in 0..config.insertion.extra_weight_optimisation_steps { 259 stats.inserted += 1;
260 // Do extra weight optimisation step heuristic 260 }
261 let Pair(v, _z_tmp) = f.differential(Pair(&μ, &z)); 261 }
262 τv = v * τ; 262
263 prox_penalty.reweigh( 263 for _ in 0..config.insertion.extra_weight_optimisation_steps {
264 &mut μ, 264 // Do extra weight optimisation step heuristic
265 &mut τv, 265 let Pair(v, mut _z_tmp) = f.differential(Pair(&μ, &z));
266 τ, 266 τv = v * τ;
267 ε, 267 prox_penalty.reweigh(
268 &config.insertion, 268 &mut μ,
269 &reg, 269 &mut τv,
270 &state, 270 τ,
271 &mut stats, 271 ε,
272 )?; 272 &config.insertion,
273 //(z, y) = zy_step(z, y, z_tmp); 273 &reg,
274 } 274 &state,
275 275 &mut stats,
276 if config.insertion.extra_weight_optimisation_steps > 0 { 276 )?;
277 // Prune spikes with zero weight. 277
278 // opKz_adj.apply_add(&mut z_tmp, &y);
279 // z_tmp.axpy(1.0, &z, -σ_p);
280 // let z_new = fnR.prox(σ_p, z_tmp);
281 // z.axpy(1.0 + ω, &z_new, -ω);
282 // //z = (z - &z_new) * (-ω) + &z_new;
283 // opKz.gemv(&mut y, σ_d, z, 1.0);
284 // y = starH.prox(σ_d, y);
285 // z = z_new;
286 }
287 Ok(())
288 })?;
289
290 if did_merge.is_none() {
278 stats.pruned += prune_with_stats(&mut μ); 291 stats.pruned += prune_with_stats(&mut μ);
279 } 292 }
280 293
281 // Update step length parameters 294 // Update step length parameters
282 // let ω = pdpsconfig.acceleration.accelerate(&mut τ, &mut σ, γ); 295 // let ω = pdpsconfig.acceleration.accelerate(&mut τ, &mut σ, γ);
301 }; 314 };
302 315
303 μ.merge_spikes_fitness(config.insertion.final_merging_method(), fit, |&v| v); 316 μ.merge_spikes_fitness(config.insertion.final_merging_method(), fit, |&v| v);
304 μ.prune(); 317 μ.prune();
305 Ok(Pair(μ, z)) 318 Ok(Pair(μ, z))
319 }
320
321 #[deprecated]
322 pub fn pointsource_forward_pdps_pair<
323 F,
324 I,
325 S,
326 Dat,
327 Reg,
328 P,
329 Z,
330 R,
331 Y,
332 /*KOpM, */ KOpZ,
333 H,
334 Plot,
335 const N: usize,
336 >(
337 f: &Dat,
338 reg: &Reg,
339 prox_penalty: &P,
340 config: &ForwardPDPSConfig<F>,
341 iterator: I,
342 plotter: Plot,
343 init: (Option<RNDM<N, F>>, Z, Y),
344 //opKμ : KOpM,
345 opKz: &KOpZ,
346 fnR: &R,
347 fnH: &H,
348 ) -> DynResult<MeasureZ<F, Z, N>>
349 where
350 F: Float + ToNalgebraRealField,
351 I: AlgIteratorFactory<IterInfo<F>>,
352 Dat: DifferentiableMapping<MeasureZ<F, Z, N>, Codomain = F, DerivativeDomain = Pair<S, Z>>,
353 //Pair<S, Z>: ClosedMul<F>, // Doesn't really need to be closed, if make this signature more complex…
354 S: DifferentiableRealMapping<N, F> + ClosedMul<F>,
355 RNDM<N, F>: SpikeMerging<F>,
356 Reg: RegTerm<Loc<N, F>, F>,
357 P: ProxPenalty<Loc<N, F>, S, Reg, F>,
358 for<'a> Pair<&'a P, &'a IdOp<Z>>: StepLengthBoundPair<F, Dat>,
359 KOpZ: BoundedLinear<Z, L2, L2, F, Codomain = Y>
360 + GEMV<F, Z, Y>
361 + SimplyAdjointable<Z, Y, Codomain = Y, AdjointCodomain = Z>,
362 KOpZ::SimpleAdjoint: GEMV<F, Y, Z>,
363 Y: ClosedEuclidean<F>,
364 for<'b> &'b Y: Instance<Y>,
365 Z: ClosedEuclidean<F> + AXPY,
366 for<'b> &'b Z: Instance<Z>,
367 R: Prox<Z, Codomain = F>,
368 H: Conjugable<Y, F, Codomain = F>,
369 for<'b> H::Conjugate<'b>: Prox<Y>,
370 Plot: Plotter<P::ReturnMapping, S, RNDM<N, F>>,
371 {
372 pointsource_forward_pdps_pair_dom(
373 f,
374 reg,
375 prox_penalty,
376 config,
377 iterator,
378 plotter,
379 init,
380 opKz,
381 fnR,
382 fnH,
383 &mut FullSpace,
384 )
306 } 385 }
307 386
308 /// Iteratively solve the pointsource localisation with an additional variable 387 /// Iteratively solve the pointsource localisation with an additional variable
309 /// using forward-backward splitting. 388 /// using forward-backward splitting.
310 /// 389 ///
311 /// The implementation uses [`pointsource_forward_pdps_pair`] with appropriate dummy 390 /// The implementation uses [`pointsource_forward_pdps_pair`] with appropriate dummy
312 /// variables, operators, and functions. 391 /// variables, operators, and functions.
313 #[replace_float_literals(F::cast_from(literal))] 392 #[replace_float_literals(F::cast_from(literal))]
314 pub fn pointsource_fb_pair<F, I, S, Dat, Reg, P, Z, R, Plot, const N: usize>( 393 pub fn pointsource_fb_pair_dom<F, I, S, Dat, Reg, P, Z, R, Plot, const N: usize>(
315 f: &Dat, 394 f: &Dat,
316 reg: &Reg, 395 reg: &Reg,
317 prox_penalty: &P, 396 prox_penalty: &P,
318 config: &FBConfig<F>, 397 config: &FBConfig<F>,
319 iterator: I, 398 iterator: I,
320 plotter: Plot, 399 plotter: Plot,
321 (μ0, z): (Option<RNDM<N, F>>, Z), 400 (μ0, z): (Option<RNDM<N, F>>, Z),
322 //opKμ : KOpM, 401 //opKμ : KOpM,
323 fnR: &R, 402 fnR: &R,
403 domain: &mut impl AdmissibleDomain<Loc<N, F>>,
324 ) -> DynResult<MeasureZ<F, Z, N>> 404 ) -> DynResult<MeasureZ<F, Z, N>>
325 where 405 where
326 F: Float + ToNalgebraRealField, 406 F: Float + ToNalgebraRealField,
327 I: AlgIteratorFactory<IterInfo<F>>, 407 I: AlgIteratorFactory<IterInfo<F>>,
328 Dat: DifferentiableMapping<MeasureZ<F, Z, N>, Codomain = F, DerivativeDomain = Pair<S, Z>>, 408 Dat: DifferentiableMapping<MeasureZ<F, Z, N>, Codomain = F, DerivativeDomain = Pair<S, Z>>,
343 // Convert config. We don't implement From (that could be done with the o2o crate), as σd0 423 // Convert config. We don't implement From (that could be done with the o2o crate), as σd0
344 // needs to be chosen in a general case; for the problem of this fucntion, anything is valid. 424 // needs to be chosen in a general case; for the problem of this fucntion, anything is valid.
345 let &FBConfig { τ0, σp0, insertion } = config; 425 let &FBConfig { τ0, σp0, insertion } = config;
346 let pdps_config = ForwardPDPSConfig { τ0, σp0, insertion, σd0: 0.0 }; 426 let pdps_config = ForwardPDPSConfig { τ0, σp0, insertion, σd0: 0.0 };
347 427
348 pointsource_forward_pdps_pair( 428 pointsource_forward_pdps_pair_dom(
349 f, 429 f,
350 reg, 430 reg,
351 prox_penalty, 431 prox_penalty,
352 &pdps_config, 432 &pdps_config,
353 iterator, 433 iterator,
354 plotter, 434 plotter,
355 (μ0, z, Loc([])), 435 (μ0, z, Loc([])),
356 &opKz, 436 &opKz,
357 fnR, 437 fnR,
358 &fnH, 438 &fnH,
439 domain,
359 ) 440 )
360 } 441 }
442
443 #[deprecated]
444 #[replace_float_literals(F::cast_from(literal))]
445 pub fn pointsource_fb_pair<F, I, S, Dat, Reg, P, Z, R, Plot, const N: usize>(
446 f: &Dat,
447 reg: &Reg,
448 prox_penalty: &P,
449 config: &FBConfig<F>,
450 iterator: I,
451 plotter: Plot,
452 init: (Option<RNDM<N, F>>, Z),
453 //opKμ : KOpM,
454 fnR: &R,
455 ) -> DynResult<MeasureZ<F, Z, N>>
456 where
457 F: Float + ToNalgebraRealField,
458 I: AlgIteratorFactory<IterInfo<F>>,
459 Dat: DifferentiableMapping<MeasureZ<F, Z, N>, Codomain = F, DerivativeDomain = Pair<S, Z>>,
460 S: DifferentiableRealMapping<N, F> + ClosedMul<F>,
461 RNDM<N, F>: SpikeMerging<F>,
462 Reg: RegTerm<Loc<N, F>, F>,
463 P: ProxPenalty<Loc<N, F>, S, Reg, F>,
464 for<'a> Pair<&'a P, &'a IdOp<Z>>: StepLengthBoundPair<F, Dat>,
465 Z: ClosedEuclidean<F> + AXPY<Field = F> + Clone,
466 for<'b> &'b Z: Instance<Z>,
467 R: Prox<Z, Codomain = F>,
468 Plot: Plotter<P::ReturnMapping, S, RNDM<N, F>>,
469 // We should not need to explicitly require this:
470 for<'b> &'b Loc<0, F>: Instance<Loc<0, F>>,
471 {
472 pointsource_fb_pair_dom(
473 f,
474 reg,
475 prox_penalty,
476 config,
477 iterator,
478 plotter,
479 init,
480 fnR,
481 &mut FullSpace,
482 )
483 }

mercurial