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 }, |