159 }); |
159 }); |
160 |
160 |
161 iters |
161 iters |
162 } |
162 } |
163 |
163 |
|
164 /// Alternative PDPS implementation of [`l1squared_unconstrained`]. |
|
165 /// For detailed documentation of the inputs and outputs, refer to there. |
|
166 /// |
|
167 /// By not dualising the 1-norm, this should produce more sparse solutions than |
|
168 /// [`l1squared_unconstrained_pdps`]. |
|
169 /// |
|
170 /// The `λ` component of the model is handled in the proximal step instead of the gradient step |
|
171 /// for potential performance improvements. |
|
172 /// The parameter `θ` is used to multiply the rescale the operator (identity) of the PDPS model. |
|
173 /// We rewrite |
|
174 /// <div>$$ |
|
175 /// \begin{split} |
|
176 /// & \min_{x ∈ ℝ^n} \frac{β}{2} |x-y|_1^2 - g^⊤ x + λ\|x\|₁ \\ |
|
177 /// & = \min_{x ∈ ℝ^n} \max_{w} ⟨θ w, x⟩ - g^⊤ x + λ\|x\|₁ |
|
178 /// - \left(x ↦ \frac{β}{2θ} |x-y|_1^2 \right)^*(w). |
|
179 /// \end{split} |
|
180 /// $$</div> |
|
181 #[replace_float_literals(F::cast_from(literal).to_nalgebra_mixed())] |
|
182 pub fn l1squared_unconstrained_pdps_alt<F, I>( |
|
183 y : &DVector<F::MixedType>, |
|
184 g : &DVector<F::MixedType>, |
|
185 λ_ : F, |
|
186 β_ : F, |
|
187 x : &mut DVector<F::MixedType>, |
|
188 τ_ : F, |
|
189 σ_ : F, |
|
190 θ_ : F, |
|
191 iterator : I |
|
192 ) -> usize |
|
193 where F : Float + ToNalgebraRealField, |
|
194 I : AlgIteratorFactory<F> |
|
195 { |
|
196 let λ = λ_.to_nalgebra_mixed(); |
|
197 let τ = τ_.to_nalgebra_mixed(); |
|
198 let σ = σ_.to_nalgebra_mixed(); |
|
199 let θ = θ_.to_nalgebra_mixed(); |
|
200 let β = β_.to_nalgebra_mixed(); |
|
201 let σθ = σ*θ; |
|
202 let τθ = τ*θ; |
|
203 let mut w = DVector::zeros(x.len()); |
|
204 let mut tmp = DVector::zeros(x.len()); |
|
205 let mut xprev = x.clone(); |
|
206 let mut iters = 0; |
|
207 |
|
208 iterator.iterate(|state| { |
|
209 // Primal step: x^{k+1} = soft_τλ(x^k - τ(θ w^k -g)) |
|
210 x.axpy(-τθ, &w, 1.0); |
|
211 x.axpy(τ, g, 1.0); |
|
212 x.apply(|x_i| *x_i = soft_thresholding(*x_i, τ*λ)); |
|
213 |
|
214 // Dual step: with g(x) = (β/(2θ))‖x-y‖₁² and q = w^k + σ(2x^{k+1}-x^k), |
|
215 // we compute w^{k+1} = prox_{σg^*}(q) for |
|
216 // = q - σ prox_{g/σ}(q/σ) |
|
217 // = q - σ prox_{(β/(2θσ))‖.-y‖₁²}(q/σ) |
|
218 // = σ(q/σ - prox_{(β/(2θσ))‖.-y‖₁²}(q/σ)) |
|
219 // where q/σ = w^k/σ + (2x^{k+1}-x^k), |
|
220 w /= σ; |
|
221 w.axpy(2.0, x, 1.0); |
|
222 w.axpy(-1.0, &xprev, 1.0); |
|
223 xprev.copy_from(&w); // use xprev as temporary variable |
|
224 l1squared_prox(&mut tmp, &mut xprev, y, β/σθ); |
|
225 w -= &xprev; |
|
226 w *= σ; |
|
227 xprev.copy_from(x); |
|
228 |
|
229 iters += 1; |
|
230 |
|
231 state.if_verbose(|| { |
|
232 F::from_nalgebra_mixed(min_subdifferential(y, x, g, λ, β)) |
|
233 }) |
|
234 }); |
|
235 |
|
236 iters |
|
237 } |
|
238 |
164 |
239 |
165 /// This function applies an iterative method for the solution of the problem |
240 /// This function applies an iterative method for the solution of the problem |
166 /// <div>$$ |
241 /// <div>$$ |
167 /// \min_{x ∈ ℝ^n} \frac{β}{2} |x-y|_1^2 - g^⊤ x + λ\|x\|₁. |
242 /// \min_{x ∈ ℝ^n} \frac{β}{2} |x-y|_1^2 - g^⊤ x + λ\|x\|₁. |
168 /// $$</div> |
243 /// $$</div> |
180 iterator : I |
255 iterator : I |
181 ) -> usize |
256 ) -> usize |
182 where F : Float + ToNalgebraRealField, |
257 where F : Float + ToNalgebraRealField, |
183 I : AlgIteratorFactory<F> |
258 I : AlgIteratorFactory<F> |
184 { |
259 { |
185 // Estimate of ‖K‖ for K=Id. |
260 // Estimate of ‖K‖ for K=θ Id. |
186 let normest = 1.0; |
261 let inner_θ = 1.0; |
|
262 let normest = inner_θ; |
187 |
263 |
188 let (inner_τ, inner_σ) = (inner.pdps_τσ0.0 / normest, inner.pdps_τσ0.1 / normest); |
264 let (inner_τ, inner_σ) = (inner.pdps_τσ0.0 / normest, inner.pdps_τσ0.1 / normest); |
189 |
265 |
190 match inner.method { |
266 match inner.method { |
191 InnerMethod::PDPS => |
267 InnerMethod::PDPS => |
192 l1squared_unconstrained_pdps(y, g, λ, β, x, inner_τ, inner_σ, iterator), |
268 l1squared_unconstrained_pdps_alt(y, g, λ, β, x, inner_τ, inner_σ, inner_θ, iterator), |
193 other => unimplemented!("${other:?} is unimplemented"), |
269 other => unimplemented!("${other:?} is unimplemented"), |
194 } |
270 } |
195 } |
271 } |