| 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); |
| 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>, |
| 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 ®, |
1115 ®, |
| 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 ®, |
1135 &config.insertion, |
| 1139 &state, |
1136 ®, |
| 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 } |