| 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 ®, |
306 ®, |
| 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>>, |