| 322 } |
322 } |
| 323 |
323 |
| 324 /// Alternative PDPS implementation of [`l1squared_nonneg`]. |
324 /// Alternative PDPS implementation of [`l1squared_nonneg`]. |
| 325 /// For detailed documentation of the inputs and outputs, refer to there. |
325 /// For detailed documentation of the inputs and outputs, refer to there. |
| 326 /// |
326 /// |
| |
327 /// By not dualising the 1-norm, this should produce more sparse solutions than |
| |
328 /// [`l1squared_nonneg_pdps`]. |
| |
329 /// |
| 327 /// The `λ` component of the model is handled in the proximal step instead of the gradient step |
330 /// The `λ` component of the model is handled in the proximal step instead of the gradient step |
| 328 /// for potential performance improvements. |
331 /// for potential performance improvements. |
| 329 /// The parameter `θ` is used to multiply the rescale the operator (identity) of the PDPS model. |
332 /// The parameter `θ` is used to multiply the rescale the operator (identity) of the PDPS model. |
| |
333 /// We rewrite |
| |
334 /// <div>$$ |
| |
335 /// \begin{split} |
| |
336 /// & \min_{x ∈ ℝ^n} \frac{β}{2} |x-y|_1^2 - g^⊤ x + λ\|x\|₁ + δ_{≥ 0}(x) \\ |
| |
337 /// & = \min_{x ∈ ℝ^n} \max_{w} ⟨θ w, x⟩ - g^⊤ x + λ\|x\|₁ + δ_{≥ 0}(x) |
| |
338 /// - \left(x ↦ \frac{β}{2θ} |x-y|_1^2 \right)^*(w). |
| |
339 /// \end{split} |
| |
340 /// $$</div> |
| 330 #[replace_float_literals(F::cast_from(literal).to_nalgebra_mixed())] |
341 #[replace_float_literals(F::cast_from(literal).to_nalgebra_mixed())] |
| 331 pub fn l1squared_nonneg_pdps_alt<F, I>( |
342 pub fn l1squared_nonneg_pdps_alt<F, I>( |
| 332 y : &DVector<F::MixedType>, |
343 y : &DVector<F::MixedType>, |
| 333 g : &DVector<F::MixedType>, |
344 g : &DVector<F::MixedType>, |
| 334 λ_ : F, |
345 λ_ : F, |
| 345 let λ = λ_.to_nalgebra_mixed(); |
356 let λ = λ_.to_nalgebra_mixed(); |
| 346 let τ = τ_.to_nalgebra_mixed(); |
357 let τ = τ_.to_nalgebra_mixed(); |
| 347 let σ = σ_.to_nalgebra_mixed(); |
358 let σ = σ_.to_nalgebra_mixed(); |
| 348 let θ = θ_.to_nalgebra_mixed(); |
359 let θ = θ_.to_nalgebra_mixed(); |
| 349 let β = β_.to_nalgebra_mixed(); |
360 let β = β_.to_nalgebra_mixed(); |
| 350 let βdivθ = β / θ; |
|
| 351 let σθ = σ*θ; |
361 let σθ = σ*θ; |
| 352 let τθ = τ*θ; |
362 let τθ = τ*θ; |
| 353 let mut w = DVector::zeros(x.len()); |
363 let mut w = DVector::zeros(x.len()); |
| 354 let mut tmp = DVector::zeros(x.len()); |
364 let mut tmp = DVector::zeros(x.len()); |
| 355 let mut xprev = x.clone(); |
365 let mut xprev = x.clone(); |
| 359 // Primal step: x^{k+1} = nonnegsoft_τλ(x^k - τ(θ w^k -g)) |
369 // Primal step: x^{k+1} = nonnegsoft_τλ(x^k - τ(θ w^k -g)) |
| 360 x.axpy(-τθ, &w, 1.0); |
370 x.axpy(-τθ, &w, 1.0); |
| 361 x.axpy(τ, g, 1.0); |
371 x.axpy(τ, g, 1.0); |
| 362 x.apply(|x_i| *x_i = nonneg_soft_thresholding(*x_i, τ*λ)); |
372 x.apply(|x_i| *x_i = nonneg_soft_thresholding(*x_i, τ*λ)); |
| 363 |
373 |
| 364 // Dual step: w^{k+1} = prox_{σ[(β/2)‖./θ-y‖₁²]^*}(q) for q = w^k + σθ(2x^{k+1}-x^k) |
374 // Dual step: with g(x) = (β/(2θ))‖x-y‖₁² and q = w^k + σ(2x^{k+1}-x^k), |
| 365 // = q - σ prox_{(β/(2σ))‖./θ-y‖₁²}(q/σ) |
375 // we compute w^{k+1} = prox_{σg^*}(q) for |
| 366 // = q - (σθ) prox_{(β/(2σθ^2))‖.-y‖₁²}(q/(σθ)) |
376 // = q - σ prox_{g/σ}(q/σ) |
| 367 // = σθ(q/(σθ) - prox_{(β/(2σθ^2))‖.-y‖₁²}(q/(σθ)) |
377 // = q - σ prox_{(β/(2θσ))‖.-y‖₁²}(q/σ) |
| 368 w /= σθ; |
378 // = σ(q/σ - prox_{(β/(2θσ))‖.-y‖₁²}(q/σ)) |
| |
379 // where q/σ = w^k/σ + (2x^{k+1}-x^k), |
| |
380 w /= σ; |
| 369 w.axpy(2.0, x, 1.0); |
381 w.axpy(2.0, x, 1.0); |
| 370 w.axpy(-1.0, &xprev, 1.0); |
382 w.axpy(-1.0, &xprev, 1.0); |
| 371 xprev.copy_from(&w); // use xprev as temporary variable |
383 xprev.copy_from(&w); // use xprev as temporary variable |
| 372 l1squared_prox(&mut tmp, &mut xprev, y, βdivθ/σθ); |
384 l1squared_prox(&mut tmp, &mut xprev, y, β/σθ); |
| 373 w -= &xprev; |
385 w -= &xprev; |
| 374 w *= σθ; |
386 w *= σ; |
| 375 xprev.copy_from(x); |
387 xprev.copy_from(x); |
| 376 |
388 |
| 377 iters +=1; |
389 iters += 1; |
| 378 |
390 |
| 379 state.if_verbose(|| { |
391 state.if_verbose(|| { |
| 380 F::from_nalgebra_mixed(min_subdifferential(y, x, g, λ, β)) |
392 F::from_nalgebra_mixed(min_subdifferential(y, x, g, λ, β)) |
| 381 }) |
393 }) |
| 382 }); |
394 }); |
| 404 where F : Float + ToNalgebraRealField, |
416 where F : Float + ToNalgebraRealField, |
| 405 I : AlgIteratorFactory<F> |
417 I : AlgIteratorFactory<F> |
| 406 { |
418 { |
| 407 match inner.method { |
419 match inner.method { |
| 408 InnerMethod::PDPS => { |
420 InnerMethod::PDPS => { |
| 409 let inner_θ = 0.001; |
421 let inner_θ = 1.0; |
| 410 // Estimate of ‖K‖ for K=θ\Id. |
422 // Estimate of ‖K‖ for K=θ\Id. |
| 411 let normest = inner_θ; |
423 let normest = inner_θ; |
| 412 let (inner_τ, inner_σ) = (inner.pdps_τσ0.0 / normest, inner.pdps_τσ0.1 / normest); |
424 let (inner_τ, inner_σ) = (inner.pdps_τσ0.0 / normest, inner.pdps_τσ0.1 / normest); |
| 413 l1squared_nonneg_pdps_alt(y, g, λ, β, x, inner_τ, inner_σ, inner_θ, iterator) |
425 l1squared_nonneg_pdps_alt(y, g, λ, β, x, inner_τ, inner_σ, inner_θ, iterator) |
| 414 }, |
426 }, |