src/sliding_fb.rs

changeset 89
8d1c959432c8
parent 84
edb5de5d5bd6
child 91
47d495348e38
equal deleted inserted replaced
88:51dbb2cc25d9 89:8d1c959432c8
9 //use nalgebra::{DVector, DMatrix}; 9 //use nalgebra::{DVector, DMatrix};
10 use itertools::izip; 10 use itertools::izip;
11 use std::iter::Iterator; 11 use std::iter::Iterator;
12 use std::ops::MulAssign; 12 use std::ops::MulAssign;
13 13
14 use crate::domain::{AdmissibleDomain, FullSpace};
14 use crate::fb::*; 15 use crate::fb::*;
15 use crate::forward_model::{BoundedCurvature, BoundedCurvatureGuess}; 16 use crate::forward_model::{BoundedCurvature, BoundedCurvatureGuess};
16 use crate::measures::merging::SpikeMerging; 17 use crate::measures::merging::SpikeMerging;
17 use crate::measures::{DeltaMeasure, DiscreteMeasure, Radon, RNDM}; 18 use crate::measures::{DeltaMeasure, DiscreteMeasure, Radon, RNDM};
18 use crate::plot::Plotter; 19 use crate::plot::Plotter;
26 use alg_tools::instance::Space; 27 use alg_tools::instance::Space;
27 use alg_tools::iterate::AlgIteratorFactory; 28 use alg_tools::iterate::AlgIteratorFactory;
28 use alg_tools::mapping::{DifferentiableMapping, DifferentiableRealMapping, Mapping, RealMapping}; 29 use alg_tools::mapping::{DifferentiableMapping, DifferentiableRealMapping, Mapping, RealMapping};
29 use alg_tools::nalgebra_support::ToNalgebraRealField; 30 use alg_tools::nalgebra_support::ToNalgebraRealField;
30 use alg_tools::norms::Norm; 31 use alg_tools::norms::Norm;
31 use alg_tools::sets::{Set, Cube};
32 use anyhow::ensure; 32 use anyhow::ensure;
33 use std::ops::ControlFlow; 33 use std::ops::ControlFlow;
34 34
35 /// Transport settings for [`pointsource_sliding_fb_reg`]. 35 /// Transport settings for [`pointsource_sliding_fb_reg`].
36 #[derive(Clone, Copy, Eq, PartialEq, Serialize, Deserialize, Debug)] 36 #[derive(Clone, Copy, Eq, PartialEq, Serialize, Deserialize, Debug)]
221 /// transport is generally preferred. If this is set to `true`, different 221 /// transport is generally preferred. If this is set to `true`, different
222 /// transport adaptation heuristics will be used. 222 /// transport adaptation heuristics will be used.
223 const MINIMAL_PARTIAL_TRANSPORT: bool = true; 223 const MINIMAL_PARTIAL_TRANSPORT: bool = true;
224 const NEW_APPROACH: bool = true; 224 const NEW_APPROACH: bool = true;
225 225
226 pub trait TransportProxPenalty<Domain, PreadjointCodomain, Reg, F = f64>: 226 pub trait TransportProxPenalty<Point, PreadjointCodomain, Reg, F = f64>:
227 ProxPenalty<Domain, PreadjointCodomain, Reg, F> 227 ProxPenalty<Point, PreadjointCodomain, Reg, F>
228 where 228 where
229 F: Float + ToNalgebraRealField, 229 F: Float + ToNalgebraRealField,
230 Reg: SlidingRegTerm<Domain, F>, 230 Reg: SlidingRegTerm<Point, F>,
231 Domain: Space + Clone, 231 Point: Space + Clone,
232 { 232 {
233 type TransportStepLength; 233 type TransportStepLength;
234 type Dom : Set<Domain>;
235 234
236 /// Constrution of initial transport `γ1` from initial measure `μ` and `v=F'(μ)` 235 /// Constrution of initial transport `γ1` from initial measure `μ` and `v=F'(μ)`
237 /// with step lengh τ and transport step length `θ_or_adaptive`. 236 /// with step lengh τ and transport step length `θ_or_adaptive`.
238 fn initial_transport( 237 fn initial_transport<Dom: AdmissibleDomain<Point>>(
239 &self, 238 &self,
240 γ: &mut Transport<Domain, F>, 239 γ: &mut Transport<Point, F>,
241 μ: &DiscreteMeasure<Domain, F>, 240 μ: &DiscreteMeasure<Point, F>,
242 ε: F, 241 ε: F,
243 τ: F, 242 τ: F,
244 τθ_or_adaptive: &mut Self::TransportStepLength, 243 τθ_or_adaptive: &mut Self::TransportStepLength,
245 v: &PreadjointCodomain, 244 v: &PreadjointCodomain,
246 tconfig: &TransportConfig<F>, 245 tconfig: &TransportConfig<F>,
247 domain: Option<&Self::Dom>, 246 domain: &Dom,
248 ); 247 );
249 248
250 /// A posteriori transport adaptation. 249 /// A posteriori transport adaptation.
251 fn aposteriori_transport( 250 fn aposteriori_transport(
252 &self, 251 &self,
253 γ: &mut Transport<Domain, F>, 252 γ: &mut Transport<Point, F>,
254 μ: &DiscreteMeasure<Domain, F>, 253 μ: &DiscreteMeasure<Point, F>,
255 μ̆: &DiscreteMeasure<Domain, F>, 254 μ̆: &DiscreteMeasure<Point, F>,
256 τv̆: &mut PreadjointCodomain, 255 τv̆: &mut PreadjointCodomain,
257 v: &mut PreadjointCodomain, 256 v: &mut PreadjointCodomain,
258 extra: Option<F>, 257 extra: Option<F>,
259 ε: F, 258 ε: F,
260 τ: F, 259 τ: F,
282 M: MinMaxMapping<Loc<N, F>, F> + DifferentiableRealMapping<N, F>, 281 M: MinMaxMapping<Loc<N, F>, F> + DifferentiableRealMapping<N, F>,
283 Reg: SlidingRegTerm<Loc<N, F>, F>, 282 Reg: SlidingRegTerm<Loc<N, F>, F>,
284 RNDM<N, F>: SpikeMerging<F>, 283 RNDM<N, F>: SpikeMerging<F>,
285 { 284 {
286 type TransportStepLength = TransportStepLength<F>; 285 type TransportStepLength = TransportStepLength<F>;
287 type Dom = Cube<N, F>;
288 286
289 fn get_transport_steplength( 287 fn get_transport_steplength(
290 &self, 288 &self,
291 (ℓ_F, maybe_ℓ_gradv, _maybe_transport_lip): (DynResult<F>, DynResult<F>, DynResult<F>), 289 (ℓ_F, maybe_ℓ_gradv, _maybe_transport_lip): (DynResult<F>, DynResult<F>, DynResult<F>),
292 tconfig: &TransportConfig<F>, 290 tconfig: &TransportConfig<F>,
299 ℓ + ℓ_F.unwrap_or(0.0), 297 ℓ + ℓ_F.unwrap_or(0.0),
300 ℓ_base_max_transport, 298 ℓ_base_max_transport,
301 ) 299 )
302 } 300 }
303 301
304 fn initial_transport( 302 fn initial_transport<Dom: AdmissibleDomain<Loc<N, F>>>(
305 &self, 303 &self,
306 γ: &mut Transport<Loc<N, F>, F>, 304 γ: &mut Transport<Loc<N, F>, F>,
307 μ: &RNDM<N, F>, 305 μ: &RNDM<N, F>,
308 _ε: F, 306 _ε: F,
309 _τ: F, 307 _τ: F,
310 τθ_or_adaptive: &mut TransportStepLength<F>, 308 τθ_or_adaptive: &mut TransportStepLength<F>,
311 v: &M, 309 v: &M,
312 tconfig: &TransportConfig<F>, 310 tconfig: &TransportConfig<F>,
313 domain: Option<&Cube<N, F>>, 311 domain: &Dom,
314 ) { 312 ) {
315 γ.do_init_transport(v, μ, τθ_or_adaptive, tconfig, domain); 313 γ.do_init_transport(v, μ, τθ_or_adaptive, tconfig, domain);
316 } 314 }
317 315
318 fn aposteriori_transport( 316 fn aposteriori_transport(
390 Reg: SlidingRegTerm<Loc<N, F>, F>, 388 Reg: SlidingRegTerm<Loc<N, F>, F>,
391 Self: ProxPenalty<Loc<N, F>, M, Reg, F>, 389 Self: ProxPenalty<Loc<N, F>, M, Reg, F>,
392 RNDM<N, F>: SpikeMerging<F>, 390 RNDM<N, F>: SpikeMerging<F>,
393 { 391 {
394 type TransportStepLength = TransportStepLength<F>; 392 type TransportStepLength = TransportStepLength<F>;
395 type Dom = Cube<N, F>;
396 393
397 fn get_transport_steplength( 394 fn get_transport_steplength(
398 &self, 395 &self,
399 (ℓ_F, maybe_ℓ_gradv, _maybe_transport_lip): (DynResult<F>, DynResult<F>, DynResult<F>), 396 (ℓ_F, maybe_ℓ_gradv, _maybe_transport_lip): (DynResult<F>, DynResult<F>, DynResult<F>),
400 tconfig: &TransportConfig<F>, 397 tconfig: &TransportConfig<F>,
407 ℓ_base + ℓ_F.unwrap_or(0.0), 404 ℓ_base + ℓ_F.unwrap_or(0.0),
408 ℓ_base_max_transport, 405 ℓ_base_max_transport,
409 ) 406 )
410 } 407 }
411 408
412 fn initial_transport( 409 fn initial_transport<Dom: AdmissibleDomain<Loc<N, F>>>(
413 &self, 410 &self,
414 γ: &mut Transport<Loc<N, F>, F>, 411 γ: &mut Transport<Loc<N, F>, F>,
415 μ: &RNDM<N, F>, 412 μ: &RNDM<N, F>,
416 _ε: F, 413 _ε: F,
417 _τ: F, 414 _τ: F,
418 τθ_or_adaptive: &mut TransportStepLength<F>, 415 τθ_or_adaptive: &mut TransportStepLength<F>,
419 v: &M, 416 v: &M,
420 tconfig: &TransportConfig<F>, 417 tconfig: &TransportConfig<F>,
421 domain: Option<&Cube<N, F>>, 418 domain: &Dom,
422 ) { 419 ) {
423 γ.do_init_transport(v, μ, τθ_or_adaptive, tconfig, domain); 420 γ.do_init_transport(v, μ, τθ_or_adaptive, tconfig, domain);
424 } 421 }
425 422
426 fn aposteriori_transport( 423 fn aposteriori_transport(
743 self.vec.retain(|ρ| ρ.retain); 740 self.vec.retain(|ρ| ρ.retain);
744 assert!(self.vec.len() <= μ.len()); 741 assert!(self.vec.len() <= μ.len());
745 } 742 }
746 743
747 /// Helper for initial transport. Called from [`TransportProxPenalty::initial_transport`]. 744 /// Helper for initial transport. Called from [`TransportProxPenalty::initial_transport`].
748 pub(super) fn do_init_transport<D>( 745 pub(super) fn do_init_transport<D, Dom: AdmissibleDomain<Loc<N, F>>>(
749 &mut self, 746 &mut self,
750 v: &D, 747 v: &D,
751 μ: &RNDM<N, F>, 748 μ: &RNDM<N, F>,
752 τθ_or_adaptive: &mut TransportStepLength<F>, 749 τθ_or_adaptive: &mut TransportStepLength<F>,
753 tconfig: &TransportConfig<F>, 750 tconfig: &TransportConfig<F>,
754 domain: Option<&Cube<N, F>>, 751 domain: &Dom,
755 ) where 752 ) where
756 D: DifferentiableRealMapping<N, F>, 753 D: DifferentiableRealMapping<N, F>,
757 { 754 {
758 use TransportStepLength::*; 755 use TransportStepLength::*;
759 756
817 for ρ in self.iter_mut() { 814 for ρ in self.iter_mut() {
818 if ρ.fail_count < tconfig.max_fail { 815 if ρ.fail_count < tconfig.max_fail {
819 let dv_x = v.differential(&ρ.x); 816 let dv_x = v.differential(&ρ.x);
820 let g = &dv_x * (ρ.α_γ.signum() * τθ); 817 let g = &dv_x * (ρ.α_γ.signum() * τθ);
821 let tmp = ρ.x - g; 818 let tmp = ρ.x - g;
822 ρ.y = if domain.is_none_or(|d| d.contains(&tmp)) { tmp } else { ρ.x }; 819 ρ.y = if domain.contains(&tmp) { tmp } else { ρ.x };
823 let n = g.norm2(); 820 let n = g.norm2();
824 if n >= F::EPSILON { 821 if n >= F::EPSILON {
825 // Estimate Lipschitz factor of ∇v 822 // Estimate Lipschitz factor of ∇v
826 let this_ℓ_gradv = (dv_x - v.differential(&ρ.y)).norm2() / n; 823 let this_ℓ_gradv = (dv_x - v.differential(&ρ.y)).norm2() / n;
827 *adaptive_ℓ_gradv = adaptive_ℓ_gradv.max(this_ℓ_gradv); 824 *adaptive_ℓ_gradv = adaptive_ℓ_gradv.max(this_ℓ_gradv);
843 840
844 if let Some(τθ) = simple_τθ { 841 if let Some(τθ) = simple_τθ {
845 for ρ in self.iter_mut() { 842 for ρ in self.iter_mut() {
846 if ρ.fail_count <= tconfig.max_fail { 843 if ρ.fail_count <= tconfig.max_fail {
847 let tmp = ρ.x - v.differential(&ρ.x) * (ρ.α_γ.signum() * τθ); 844 let tmp = ρ.x - v.differential(&ρ.x) * (ρ.α_γ.signum() * τθ);
848 ρ.y = if domain.is_none_or(|d| d.contains(&tmp)) { tmp } else { ρ.x }; 845 ρ.y = if domain.contains(&tmp) { tmp } else { ρ.x };
849 } 846 }
850 } 847 }
851 } 848 }
852 } 849 }
853 850
976 /// 973 ///
977 /// The parametrisation is as for [`pointsource_fb_reg`], except an additional domain restriction 974 /// The parametrisation is as for [`pointsource_fb_reg`], except an additional domain restriction
978 /// may be given. 975 /// may be given.
979 /// Inertia is currently not supported. 976 /// Inertia is currently not supported.
980 #[replace_float_literals(F::cast_from(literal))] 977 #[replace_float_literals(F::cast_from(literal))]
981 pub fn pointsource_sliding_fb_dom<F, I, Dat, Reg, Plot, P, const N: usize>( 978 pub fn pointsource_sliding_fb<F, I, Dat, Reg, Plot, P, const N: usize>(
982 f: &Dat, 979 f: &Dat,
983 reg: &Reg, 980 reg: &Reg,
984 prox_penalty: &P, 981 prox_penalty: &P,
985 config: &SlidingFBConfig<F>, 982 config: &SlidingFBConfig<F>,
986 iterator: I, 983 iterator: I,
987 mut plotter: Plot, 984 mut plotter: Plot,
988 μ0: Option<RNDM<N, F>>, 985 μ0: Option<RNDM<N, F>>,
989 domain: Option<&P::Dom>, 986 domain: &mut impl AdmissibleDomain<Loc<N, F>>,
990 ) -> DynResult<RNDM<N, F>> 987 ) -> DynResult<RNDM<N, F>>
991 where 988 where
992 F: Float + ToNalgebraRealField, 989 F: Float + ToNalgebraRealField,
993 I: AlgIteratorFactory<IterInfo<F>>, 990 I: AlgIteratorFactory<IterInfo<F>>,
994 Dat: DifferentiableMapping<RNDM<N, F>, Codomain = F> + BoundedCurvature<F>, 991 Dat: DifferentiableMapping<RNDM<N, F>, Codomain = F> + BoundedCurvature<F>,
1047 ε, 1044 ε,
1048 τ, 1045 τ,
1049 &mut τθ_or_adaptive, 1046 &mut τθ_or_adaptive,
1050 &v, 1047 &v,
1051 &config.transport, 1048 &config.transport,
1052 domain 1049 domain,
1053 ); 1050 );
1054 1051
1055 let mut attempts = 0; 1052 let mut attempts = 0;
1056 1053
1057 // Solve finite-dimensional subproblem several times until the dual variable for the 1054 // Solve finite-dimensional subproblem several times until the dual variable for the
1105 γ.get_transport_stats(&mut stats, &μ); 1102 γ.get_transport_stats(&mut stats, &μ);
1106 1103
1107 // Merge spikes. 1104 // Merge spikes.
1108 // This crucially expects the merge routine to be stable with respect to spike locations, 1105 // This crucially expects the merge routine to be stable with respect to spike locations,
1109 // and not to performing any pruning. That is be to done below simultaneously for γ. 1106 // and not to performing any pruning. That is be to done below simultaneously for γ.
1110 config.insertion.if_merge_now(&state, |ins| { 1107 let did_merge = config.insertion.if_merge_now(&state, |ins| {
1111 let m = prox_penalty.merge_spikes( 1108 stats.merged += prox_penalty.merge_spikes(
1112 &mut μ, 1109 &mut μ,
1113 &mut τv̆, 1110 &mut τv̆,
1114 &μ̆, 1111 &μ̆,
1115 τ, 1112 τ,
1116 ε, 1113 ε,
1117 ins, 1114 ins,
1118 &reg, 1115 &reg,
1119 Some(|μ̃: &RNDM<N, F>| f.apply(μ̃) + reg.apply(μ̃) ), 1116 Some(|μ̃: &RNDM<N, F>| f.apply(μ̃) + reg.apply(μ̃)),
1120 ); 1117 );
1121 //if m > 0 { 1118 γ.prune_compat(&mut μ, &mut stats);
1122 stats.merged += m; 1119
1123 //v = f.differential(&μ); 1120 if config.insertion.random_insertions {
1124 //} 1121 if let Some(x) = domain.random_point() {
1125 }); 1122 μ += DeltaMeasure { x, α: 0.0 };
1126 1123 stats.inserted += 1;
1127 γ.prune_compat(&mut μ, &mut stats); 1124 }
1128 1125 }
1129 // Do extra weight optimisation step heuristic 1126
1130 for _ in 1..config.insertion.extra_weight_optimisation_steps { 1127 // Do extra weight optimisation step heuristic
1131 τv̆ = f.differential(&μ) * τ; 1128 for _ in 1..config.insertion.extra_weight_optimisation_steps {
1132 prox_penalty.reweigh( 1129 τv̆ = f.differential(&μ) * τ;
1133 &mut μ, 1130 prox_penalty.reweigh(
1134 &mut τv̆, 1131 &mut μ,
1135 τ, 1132 &mut τv̆,
1136 ε, 1133 τ,
1137 &config.insertion, 1134 ε,
1138 &reg, 1135 &config.insertion,
1139 &state, 1136 &reg,
1140 &mut stats, 1137 &state,
1141 )?; 1138 &mut stats,
1142 } 1139 )?;
1143 1140 }
1144 if config.insertion.extra_weight_optimisation_steps > 0 { 1141 Ok(())
1142 })?;
1143
1144 if did_merge.is_none() {
1145 γ.prune_compat(&mut μ, &mut stats); 1145 γ.prune_compat(&mut μ, &mut stats);
1146 } 1146 }
1147 1147
1148 let iter = state.iteration(); 1148 let iter = state.iteration();
1149 stats.this_iters += 1; 1149 stats.this_iters += 1;
1183 RNDM<N, F>: SpikeMerging<F>, 1183 RNDM<N, F>: SpikeMerging<F>,
1184 Reg: SlidingRegTerm<Loc<N, F>, F>, 1184 Reg: SlidingRegTerm<Loc<N, F>, F>,
1185 P: TransportProxPenalty<Loc<N, F>, Dat::DerivativeDomain, Reg, F> + StepLengthBound<F, Dat>, 1185 P: TransportProxPenalty<Loc<N, F>, Dat::DerivativeDomain, Reg, F> + StepLengthBound<F, Dat>,
1186 Plot: Plotter<P::ReturnMapping, Dat::DerivativeDomain, RNDM<N, F>>, 1186 Plot: Plotter<P::ReturnMapping, Dat::DerivativeDomain, RNDM<N, F>>,
1187 { 1187 {
1188 pointsource_sliding_fb_dom(f, reg, prox_penalty, config, iterator, plotter, μ0, None) 1188 pointsource_sliding_fb(
1189 } 1189 f,
1190 reg,
1191 prox_penalty,
1192 config,
1193 iterator,
1194 plotter,
1195 μ0,
1196 &mut FullSpace,
1197 )
1198 }

mercurial