src/sliding_pdps.rs

changeset 72
e9a460a0e638
parent 68
00d0881f89a6
child 75
677a5fd1b014
equal deleted inserted replaced
71:e2953ffd4e0b 72:e9a460a0e638
6 use crate::fb::*; 6 use crate::fb::*;
7 use crate::forward_model::{BoundedCurvature, BoundedCurvatureGuess}; 7 use crate::forward_model::{BoundedCurvature, BoundedCurvatureGuess};
8 use crate::measures::merging::SpikeMerging; 8 use crate::measures::merging::SpikeMerging;
9 use crate::measures::{DiscreteMeasure, RNDM}; 9 use crate::measures::{DiscreteMeasure, RNDM};
10 use crate::plot::Plotter; 10 use crate::plot::Plotter;
11 use crate::prox_penalty::{ProxPenalty, StepLengthBoundPair}; 11 use crate::prox_penalty::StepLengthBoundPair;
12 use crate::regularisation::SlidingRegTerm; 12 use crate::regularisation::SlidingRegTerm;
13 use crate::sliding_fb::{SlidingFBConfig, Transport, TransportConfig, TransportStepLength}; 13 use crate::sliding_fb::{SlidingFBConfig, Transport, TransportConfig, TransportProxPenalty};
14 use crate::types::*; 14 use crate::types::*;
15 use alg_tools::bounds::MinMaxMapping;
15 use alg_tools::convex::{Conjugable, Prox, Zero}; 16 use alg_tools::convex::{Conjugable, Prox, Zero};
16 use alg_tools::direct_product::Pair; 17 use alg_tools::direct_product::Pair;
17 use alg_tools::error::DynResult; 18 use alg_tools::error::DynResult;
18 use alg_tools::euclidean::ClosedEuclidean; 19 use alg_tools::euclidean::ClosedEuclidean;
19 use alg_tools::iterate::AlgIteratorFactory; 20 use alg_tools::iterate::AlgIteratorFactory;
98 where 99 where
99 F: Float + ToNalgebraRealField, 100 F: Float + ToNalgebraRealField,
100 I: AlgIteratorFactory<IterInfo<F>>, 101 I: AlgIteratorFactory<IterInfo<F>>,
101 Dat: DifferentiableMapping<MeasureZ<F, Z, N>, Codomain = F, DerivativeDomain = Pair<S, Z>> 102 Dat: DifferentiableMapping<MeasureZ<F, Z, N>, Codomain = F, DerivativeDomain = Pair<S, Z>>
102 + BoundedCurvature<F>, 103 + BoundedCurvature<F>,
103 S: DifferentiableRealMapping<N, F> + ClosedMul<F>, 104 S: DifferentiableRealMapping<N, F> + ClosedMul<F> + MinMaxMapping<Loc<N, F>, F>,
104 for<'a> Pair<&'a P, &'a IdOp<Z>>: StepLengthBoundPair<F, Dat>, 105 for<'a> Pair<&'a P, &'a IdOp<Z>>: StepLengthBoundPair<F, Dat>,
105 //Pair<S, Z>: ClosedMul<F>, 106 //Pair<S, Z>: ClosedMul<F>,
106 RNDM<N, F>: SpikeMerging<F>, 107 RNDM<N, F>: SpikeMerging<F>,
107 Reg: SlidingRegTerm<Loc<N, F>, F>, 108 Reg: SlidingRegTerm<Loc<N, F>, F>,
108 P: ProxPenalty<Loc<N, F>, S, Reg, F>, 109 P: TransportProxPenalty<Loc<N, F>, S, Reg, F>,
109 // KOpM : Linear<RNDM<N, F>, Codomain=Y> 110 // KOpM : Linear<RNDM<N, F>, Codomain=Y>
110 // + GEMV<F, RNDM<N, F>> 111 // + GEMV<F, RNDM<N, F>>
111 // + Preadjointable< 112 // + Preadjointable<
112 // RNDM<N, F>, Y, 113 // RNDM<N, F>, Y,
113 // PreadjointCodomain = S, 114 // PreadjointCodomain = S,
120 + GEMV<F, Z> 121 + GEMV<F, Z>
121 + SimplyAdjointable<Z, Y, AdjointCodomain = Z>, 122 + SimplyAdjointable<Z, Y, AdjointCodomain = Z>,
122 KOpZ::SimpleAdjoint: GEMV<F, Y>, 123 KOpZ::SimpleAdjoint: GEMV<F, Y>,
123 Y: ClosedEuclidean<F>, 124 Y: ClosedEuclidean<F>,
124 for<'b> &'b Y: Instance<Y>, 125 for<'b> &'b Y: Instance<Y>,
125 Z: ClosedEuclidean<F>, 126 Z: ClosedEuclidean<F> + AXPY,
126 for<'b> &'b Z: Instance<Z>, 127 for<'b> &'b Z: Instance<Z>,
127 R: Prox<Z, Codomain = F>, 128 R: Prox<Z, Codomain = F>,
128 H: Conjugable<Y, F, Codomain = F>, 129 H: Conjugable<Y, F, Codomain = F>,
129 for<'b> H::Conjugate<'b>: Prox<Y>, 130 for<'b> H::Conjugate<'b>: Prox<Y>,
130 Plot: Plotter<P::ReturnMapping, S, RNDM<N, F>>, 131 Plot: Plotter<P::ReturnMapping, S, RNDM<N, F>>,
151 // let opAnorm = opA.opnorm_bound(PairNorm(Radon, L2, L2), L2); 152 // let opAnorm = opA.opnorm_bound(PairNorm(Radon, L2, L2), L2);
152 let bigθ = 0.0; //opKμ.transport_lipschitz_factor(L2Squared); 153 let bigθ = 0.0; //opKμ.transport_lipschitz_factor(L2Squared);
153 let bigM = 0.0; //opKμ.adjoint_product_bound(&op𝒟).unwrap().sqrt(); 154 let bigM = 0.0; //opKμ.adjoint_product_bound(&op𝒟).unwrap().sqrt();
154 let nKz = opKz.opnorm_bound(L2, L2)?; 155 let nKz = opKz.opnorm_bound(L2, L2)?;
155 let is_fb = nKz == 0.0; 156 let is_fb = nKz == 0.0;
156 let ℓ = 0.0;
157 let idOpZ = IdOp::new(); 157 let idOpZ = IdOp::new();
158 let opKz_adj = opKz.adjoint(); 158 let opKz_adj = opKz.adjoint();
159 let (l, l_z) = Pair(prox_penalty, &idOpZ).step_length_bound_pair(&f)?; 159 let (l, l_z) = Pair(prox_penalty, &idOpZ).step_length_bound_pair(&f)?;
160 160
161 // We need to satisfy 161 // We need to satisfy
181 // Now we need κ‖K_μ(π_♯^1 - π_♯^0)γ‖^2 ≤ (1/θ - τ[ℓ_F + ℓ]) ∫ c_2 dγ for κ defined as: 181 // Now we need κ‖K_μ(π_♯^1 - π_♯^0)γ‖^2 ≤ (1/θ - τ[ℓ_F + ℓ]) ∫ c_2 dγ for κ defined as:
182 let κ = τ * σ_d * ψ / ((1.0 - β) * ψ - τ * σ_d * bigM); 182 let κ = τ * σ_d * ψ / ((1.0 - β) * ψ - τ * σ_d * bigM);
183 // The factor two in the manuscript disappears due to the definition of 𝚹 being 183 // The factor two in the manuscript disappears due to the definition of 𝚹 being
184 // for ‖x-y‖₂² instead of c_2(x, y)=‖x-y‖₂²/2. 184 // for ‖x-y‖₂² instead of c_2(x, y)=‖x-y‖₂²/2.
185 185
186 let mut θ_or_adaptive = match f.curvature_bound_components(config.guess) { 186 let mut τθ_or_adaptive = prox_penalty.get_transport_steplength(
187 (_, Err(_)) => TransportStepLength::Fixed(config.transport.θ0), 187 f.curvature_bound_components(config.guess),
188 (maybe_ℓ_F, Ok(transport_lip)) => { 188 &config.transport,
189 let calculate_θτ = move |ℓ_F, max_transport| { 189 0.0,
190 let ℓ_r = transport_lip * max_transport; 190 κ * bigθ / τ, // = 0 currently
191 config.transport.θ0 / ((ℓ + ℓ_F + ℓ_r) + κ * bigθ * max_transport / τ) 191 );
192 }; 192
193 match maybe_ℓ_F {
194 Ok(ℓ_F) => TransportStepLength::AdaptiveMax {
195 l: ℓ_F, // TODO: could estimate computing the real reesidual
196 max_transport: 0.0,
197 g: calculate_θτ,
198 },
199 Err(_) => TransportStepLength::FullyAdaptive {
200 l: F::EPSILON, // Start with something very small to estimate differentials
201 max_transport: 0.0,
202 g: calculate_θτ,
203 },
204 }
205 }
206 };
207 // Acceleration is not currently supported 193 // Acceleration is not currently supported
208 // let γ = dataterm.factor_of_strong_convexity(); 194 // let γ = dataterm.factor_of_strong_convexity();
209 let ω = 1.0; 195 let ω = 1.0;
210 196
211 // We multiply tolerance by τ for FB since our subproblems depending on tolerances are scaled 197 // We multiply tolerance by τ for FB since our subproblems depending on tolerances are scaled
228 }; 214 };
229 let mut stats = IterInfo::new(); 215 let mut stats = IterInfo::new();
230 216
231 // Run the algorithm 217 // Run the algorithm
232 for state in iterator.iter_init(|| full_stats(&μ, &z, ε, stats.clone())) { 218 for state in iterator.iter_init(|| full_stats(&μ, &z, ε, stats.clone())) {
233 // Calculate initial transport 219 let Pair(mut v, _) = f.differential(Pair(&μ, &z));
234 let Pair(v, _) = f.differential(Pair(&μ, &z)); 220
235 //opKμ.preadjoint().apply_add(&mut v, y); 221 //opKμ.preadjoint().apply_add(&mut v, y);
236 // We want to proceed as in Example 4.12 but with v and v̆ as in §5. 222 // We want to proceed as in Example 4.12 but with v and v̆ as in §5.
237 // With A(ν, z) = A_μ ν + A_z z, following Example 5.1, we have 223 // With A(ν, z) = A_μ ν + A_z z, following Example 5.1, we have
238 // P_ℳ[F'(ν, z) + Ξ(ν, z, y)]= A_ν^*[A_ν ν + A_z z] + K_μ ν = A_ν^*A(ν, z) + K_μ ν, 224 // P_ℳ[F'(ν, z) + Ξ(ν, z, y)]= A_ν^*[A_ν ν + A_z z] + K_μ ν = A_ν^*A(ν, z) + K_μ ν,
239 // where A_ν^* becomes a multiplier. 225 // where A_ν^* becomes a multiplier.
240 // This is much easier with K_μ = 0, which is the only reason why are enforcing it. 226 // This is much easier with K_μ = 0, which is the only reason why are enforcing it.
241 // TODO: Write a version of initial_transport that can deal with K_μ ≠ 0. 227 // TODO: Write a version of initial_transport that can deal with K_μ ≠ 0.
242 228
243 //dbg!(&μ); 229 //dbg!(&μ);
244 230
245 γ.initial_transport(&μ, τ, &mut θ_or_adaptive, v, &config.transport); 231 prox_penalty.initial_transport(
232 &mut γ,
233 &μ,
234 ε,
235 τ,
236 &mut τθ_or_adaptive,
237 &v,
238 &config.transport,
239 );
246 240
247 let mut attempts = 0; 241 let mut attempts = 0;
248 242
249 // Solve finite-dimensional subproblem several times until the dual variable for the 243 // Solve finite-dimensional subproblem several times until the dual variable for the
250 // regularisation term conforms to the assumptions made for the transport above. 244 // regularisation term conforms to the assumptions made for the transport above.
252 // Set initial guess for μ=μ^{k+1}. 246 // Set initial guess for μ=μ^{k+1}.
253 γ.μ̆_into(&mut μ); 247 γ.μ̆_into(&mut μ);
254 let μ̆ = μ.clone(); 248 let μ̆ = μ.clone();
255 249
256 // Calculate τv̆ = τA_*(A[μ_transported + μ_transported_base]-b) 250 // Calculate τv̆ = τA_*(A[μ_transported + μ_transported_base]-b)
257 let Pair(mut τv̆, τz̆) = f.differential(Pair(&μ̆, &z)) * τ; 251 let Pair(v̆, mut z̆) = f.differential(Pair(&μ̆, &z));
252 let mut τv̆ = v̆ * τ;
258 // opKμ.preadjoint().gemv(&mut τv̆, τ, y, 1.0); 253 // opKμ.preadjoint().gemv(&mut τv̆, τ, y, 1.0);
259 254
260 // Construct μ^{k+1} by solving finite-dimensional subproblems and insert new spikes. 255 // Construct μ^{k+1} by solving finite-dimensional subproblems and insert new spikes.
261 let (maybe_d, within_tolerances) = prox_penalty.insert_and_reweigh( 256 let (maybe_d, within_tolerances) = prox_penalty.insert_and_reweigh(
262 &mut μ, 257 &mut μ,
268 &state, 263 &state,
269 &mut stats, 264 &mut stats,
270 )?; 265 )?;
271 266
272 // Do z variable primal update here to able to estimate B_{v̆^k-v^{k+1}} 267 // Do z variable primal update here to able to estimate B_{v̆^k-v^{k+1}}
273 let mut z_new = τz̆; 268 opKz_adj.apply_add(&mut z̆, &y);
274 opKz_adj.gemv(&mut z_new, -σ_p, &y, -σ_p / τ); 269 z̆.axpy(1.0, &z, -σ_p);
275 z_new = fnR.prox(σ_p, z_new + &z); 270 let z_new = fnR.prox(σ_p, z̆);
271 //let z_new = fnR.prox(σ_p, z̆ * (-σ_p) + &z);
276 272
277 // A posteriori transport adaptation. 273 // A posteriori transport adaptation.
278 if γ.aposteriori_transport( 274 if prox_penalty.aposteriori_transport(
275 &mut γ,
279 &μ, 276 &μ,
280 &μ̆, 277 &μ̆,
281 &mut τv̆, 278 &mut τv̆,
282 Some(z_new.dist2(&z)), 279 &mut v,
280 None, //Some(z_new.dist2(&z)),
283 ε, 281 ε,
282 τ,
283 &τθ_or_adaptive,
284 reg,
284 &config.transport, 285 &config.transport,
286 &config.insertion.refinement,
285 &mut attempts, 287 &mut attempts,
286 ) { 288 ) {
287 break 'adapt_transport (maybe_d, within_tolerances, τv̆, z_new, μ̆); 289 break 'adapt_transport (maybe_d, within_tolerances, τv̆, z_new, μ̆);
288 } 290 }
289 }; 291 };
292 294
293 // Merge spikes. 295 // Merge spikes.
294 // This crucially expects the merge routine to be stable with respect to spike locations, 296 // This crucially expects the merge routine to be stable with respect to spike locations,
295 // and not to performing any pruning. That is be to done below simultaneously for γ. 297 // and not to performing any pruning. That is be to done below simultaneously for γ.
296 if config.insertion.merge_now(&state) { 298 if config.insertion.merge_now(&state) {
297 stats.merged += prox_penalty.merge_spikes( 299 let m = prox_penalty.merge_spikes(
298 &mut μ, 300 &mut μ,
299 &mut τv̆, 301 &mut τv̆,
300 &μ̆, 302 &μ̆,
301 τ, 303 τ,
302 ε, 304 ε,
303 &config.insertion, 305 &config.insertion,
304 &reg, 306 &reg,
305 is_fb.then_some(|μ̃: &RNDM<N, F>| f.apply(Pair(μ̃, &z))), 307 Some(|μ̃: &RNDM<N, F>| f.apply(Pair(μ̃, &z))),
306 ); 308 );
309 if m > 0 {
310 stats.merged += m;
311 }
307 } 312 }
308 313
309 γ.prune_compat(&mut μ, &mut stats); 314 γ.prune_compat(&mut μ, &mut stats);
310 315
311 // Do dual update 316 // Do dual update
312 // opKμ.gemv(&mut y, σ_d*(1.0 + ω), &μ, 1.0); // y = y + σ_d K[(1+ω)(μ,z)^{k+1}] 317 // opKμ.gemv(&mut y, σ_d*(1.0 + ω), &μ, 1.0); // y = y + σ_d K[(1+ω)(μ,z)^{k+1}]
313 opKz.gemv(&mut y, σ_d * (1.0 + ω), &z_new, 1.0); 318 z.axpy(1.0 + ω, &z_new, -ω);
314 // opKμ.gemv(&mut y, -σ_d*ω, μ_base, 1.0);// y = y + σ_d K[(1+ω)(μ,z)^{k+1} - ω (μ,z)^k]-b 319 //z = (z - &z_new) * (-ω) + &z_new;
315 opKz.gemv(&mut y, -σ_d * ω, z, 1.0); // y = y + σ_d K[(1+ω)(μ,z)^{k+1} - ω (μ,z)^k]-b 320 opKz.gemv(&mut y, σ_d, z, 1.0);
316 y = starH.prox(σ_d, y); 321 y = starH.prox(σ_d, y);
317 z = z_new; 322 z = z_new;
318 323
319 // Update step length parameters 324 // Update step length parameters
320 // let ω = pdpsconfig.acceleration.accelerate(&mut τ, &mut σ, γ); 325 // let ω = pdpsconfig.acceleration.accelerate(&mut τ, &mut σ, γ);
362 where 367 where
363 F: Float + ToNalgebraRealField, 368 F: Float + ToNalgebraRealField,
364 I: AlgIteratorFactory<IterInfo<F>>, 369 I: AlgIteratorFactory<IterInfo<F>>,
365 Dat: DifferentiableMapping<MeasureZ<F, Z, N>, Codomain = F, DerivativeDomain = Pair<S, Z>> 370 Dat: DifferentiableMapping<MeasureZ<F, Z, N>, Codomain = F, DerivativeDomain = Pair<S, Z>>
366 + BoundedCurvature<F>, 371 + BoundedCurvature<F>,
367 S: DifferentiableRealMapping<N, F> + ClosedMul<F>, 372 S: DifferentiableRealMapping<N, F> + ClosedMul<F> + MinMaxMapping<Loc<N, F>, F>,
368 RNDM<N, F>: SpikeMerging<F>, 373 RNDM<N, F>: SpikeMerging<F>,
369 Reg: SlidingRegTerm<Loc<N, F>, F>, 374 Reg: SlidingRegTerm<Loc<N, F>, F>,
370 P: ProxPenalty<Loc<N, F>, S, Reg, F>, 375 P: TransportProxPenalty<Loc<N, F>, S, Reg, F>,
371 for<'a> Pair<&'a P, &'a IdOp<Z>>: StepLengthBoundPair<F, Dat>, 376 for<'a> Pair<&'a P, &'a IdOp<Z>>: StepLengthBoundPair<F, Dat>,
372 Z: ClosedEuclidean<F> + AXPY + Clone, 377 Z: ClosedEuclidean<F> + AXPY + Clone,
373 for<'b> &'b Z: Instance<Z>, 378 for<'b> &'b Z: Instance<Z>,
374 R: Prox<Z, Codomain = F>, 379 R: Prox<Z, Codomain = F>,
375 Plot: Plotter<P::ReturnMapping, S, RNDM<N, F>>, 380 Plot: Plotter<P::ReturnMapping, S, RNDM<N, F>>,

mercurial