src/subproblem/l1squared_nonneg.rs

branch
dev
changeset 42
6a7365d73e4c
parent 39
6316d68b58af
equal deleted inserted replaced
41:b6bdb6cb4d44 42:6a7365d73e4c
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 },

mercurial