src/subproblem/unconstrained.rs

branch
dev
changeset 34
efa60bc4f743
parent 24
d29d1fcf5423
child 39
6316d68b58af
equal deleted inserted replaced
33:aec67cdd6b14 34:efa60bc4f743
21 use crate::types::*; 21 use crate::types::*;
22 use super::{ 22 use super::{
23 InnerMethod, 23 InnerMethod,
24 InnerSettings 24 InnerSettings
25 }; 25 };
26 use super::l1squared_nonneg::max_interval_dist_to_zero;
26 27
27 /// Compute the proximal operator of $x \mapsto |x|$, i.e., the soft-thresholding operator. 28 /// Compute the proximal operator of $x \mapsto |x|$, i.e., the soft-thresholding operator.
28 #[inline] 29 #[inline]
29 #[replace_float_literals(F::cast_from(literal))] 30 #[replace_float_literals(F::cast_from(literal))]
30 fn soft_thresholding<F : Float>(v : F, λ : F) -> F { 31 pub(crate) fn soft_thresholding<F : Float>(v : F, λ : F) -> F {
31 if v > λ { 32 if v > λ {
32 v - λ 33 v - λ
33 } else if v < -λ { 34 } else if v < -λ {
34 v + λ 35 v + λ
35 } else { 36 } else {
38 } 39 }
39 40
40 /// Returns the ∞-norm minimal subdifferential of $x ↦ x^⊤Ax - g^⊤ x + λ\|x\|₁$ at $x$. 41 /// Returns the ∞-norm minimal subdifferential of $x ↦ x^⊤Ax - g^⊤ x + λ\|x\|₁$ at $x$.
41 /// 42 ///
42 /// `v` will be modified and cannot be trusted to contain useful values afterwards. 43 /// `v` will be modified and cannot be trusted to contain useful values afterwards.
43 #[replace_float_literals(F::cast_from(literal).to_nalgebra_mixed())] 44 #[replace_float_literals(F::cast_from(literal))]
44 fn min_subdifferential<F : Float + ToNalgebraRealField>( 45 fn min_subdifferential<F : Float + nalgebra::RealField>(
45 v : &mut DVector<F::MixedType>, 46 v : &mut DVector<F>,
46 mA : &DMatrix<F::MixedType>, 47 mA : &DMatrix<F>,
47 x : &DVector<F::MixedType>, 48 x : &DVector<F>,
48 g : &DVector<F::MixedType>, 49 g : &DVector<F>,
49 λ : F::MixedType 50 λ : F
50 ) -> F { 51 ) -> F {
51 v.copy_from(g); 52 v.copy_from(g);
52 mA.gemv(v, 1.0, x, -1.0); // v = Ax - g 53 mA.gemv(v, 1.0, x, -1.0); // v = Ax - g
53 let mut val = 0.0; 54 let mut val = 0.0;
54 for (&v_i, &x_i) in izip!(v.iter(), x.iter()) { 55 for (&v_i, &x_i) in izip!(v.iter(), x.iter()) {
55 // The subdifferential at x is $Ax - g + λ ∂‖·‖₁(x)$. 56 let (mut lb, mut ub) = (v_i, v_i);
56 val = val.max(match x_i.partial_cmp(&0.0) { 57 match x_i.partial_cmp(&0.0) {
57 Some(Greater) => v_i + λ, 58 Some(Greater) => { lb += λ; ub += λ },
58 Some(Less) => v_i - λ, 59 Some(Less) => { lb -= λ; ub -= λ },
59 Some(Equal) => soft_thresholding(v_i, λ), 60 Some(Equal) => { lb -= λ; ub += λ },
60 None => F::MixedType::nan(), 61 None => {},
61 }) 62 }
63 val = max_interval_dist_to_zero(val, lb, ub);
62 } 64 }
63 F::from_nalgebra_mixed(val) 65 val
64 } 66 }
65 67
66 68
67 /// Forward-backward splitting implementation of [`quadratic_unconstrained`]. 69 /// Forward-backward splitting implementation of [`quadratic_unconstrained`].
68 /// For detailed documentation of the inputs and outputs, refer to there. 70 /// For detailed documentation of the inputs and outputs, refer to there.
104 }); 106 });
105 107
106 iters +=1; 108 iters +=1;
107 109
108 backup.map(|_| { 110 backup.map(|_| {
109 min_subdifferential(&mut v, mA, x, g, λ) 111 F::from_nalgebra_mixed(min_subdifferential(&mut v, mA, x, g, λ))
110 }) 112 })
111 }); 113 });
112 114
113 iters 115 iters
114 } 116 }
240 iters += 1; 242 iters += 1;
241 243
242 // 4. Report solution quality 244 // 4. Report solution quality
243 state.if_verbose(|| { 245 state.if_verbose(|| {
244 // Calculate subdifferential at the FB step `x` that hasn't yet had `s` yet added. 246 // Calculate subdifferential at the FB step `x` that hasn't yet had `s` yet added.
245 min_subdifferential(&mut v, mA, x, g, λ) 247 F::from_nalgebra_mixed(min_subdifferential(&mut v, mA, x, g, λ))
246 }) 248 })
247 }); 249 });
248 250
249 res.map(|_| iters) 251 res.map(|_| iters)
250 } 252 }
251 253
252 /// This function applies an iterative method for the solution of the problem 254 /// This function applies an iterative method for the solution of the problem
253 /// <div>$$ 255 /// <div>$$
254 /// \min_{x ∈ ℝ^n} \frac{1}{2} x^⊤Ax - g^⊤ x + λ\|x\|₁ + c. 256 /// \min_{x ∈ ℝ^n} \frac{1}{2} x^⊤Ax - g^⊤ x + λ\|x\|₁.
255 /// $$</div> 257 /// $$</div>
256 /// Semismooth Newton or forward-backward are supported based on the setting in `method`. 258 /// Semismooth Newton or forward-backward are supported based on the setting in `method`.
257 /// The parameter `mA` is matrix $A$, and `g` and `λ` are as in the mathematical formulation. 259 /// The parameter `mA` is matrix $A$, and `g` and `λ` are as in the mathematical formulation.
258 /// The constant $c$ does not need to be provided. The step length parameter is `τ` while 260 /// The constant $c$ does not need to be provided. The step length parameter is `τ` while
259 /// `x` contains the initial iterate and on return the final one. The `iterator` controls 261 /// `x` contains the initial iterate and on return the final one. The `iterator` controls
260 /// stopping. The “verbose” value output by all methods is the $ℓ\_∞$ distance of some 262 /// stopping. The “verbose” value output by all methods is the $ℓ\_∞$ distance of some
261 /// subdifferential of the objective to zero. 263 /// subdifferential of the objective to zero.
262 /// 264 ///
263 /// This function returns the number of iterations taken. 265 /// This function returns the number of iterations taken.
264 pub fn quadratic_unconstrained<F, I>( 266 pub fn quadratic_unconstrained<F, I>(
265 method : InnerMethod,
266 mA : &DMatrix<F::MixedType>, 267 mA : &DMatrix<F::MixedType>,
267 g : &DVector<F::MixedType>, 268 g : &DVector<F::MixedType>,
268 //c_ : F,
269 λ : F, 269 λ : F,
270 x : &mut DVector<F::MixedType>, 270 x : &mut DVector<F::MixedType>,
271 τ : F, 271 mA_normest : F,
272 inner : &InnerSettings<F>,
272 iterator : I 273 iterator : I
273 ) -> usize 274 ) -> usize
274 where F : Float + ToNalgebraRealField, 275 where F : Float + ToNalgebraRealField,
275 I : AlgIteratorFactory<F> 276 I : AlgIteratorFactory<F>
276 { 277 {
278 let inner_τ = inner.fb_τ0 / mA_normest;
277 279
278 match method { 280 match inner.method {
279 InnerMethod::FB => 281 InnerMethod::FB | InnerMethod::Default =>
280 quadratic_unconstrained_fb(mA, g, λ, x, τ, iterator), 282 quadratic_unconstrained_fb(mA, g, λ, x, inner_τ, iterator),
281 InnerMethod::SSN => 283 InnerMethod::SSN =>
282 quadratic_unconstrained_ssn(mA, g, λ, x, τ, iterator).unwrap_or_else(|e| { 284 quadratic_unconstrained_ssn(mA, g, λ, x, inner_τ, iterator).unwrap_or_else(|e| {
283 println!("{}", format!("{e}. Using FB fallback.").red()); 285 println!("{}", format!("{e}. Using FB fallback.").red());
284 let ins = InnerSettings::<F>::default(); 286 let ins = InnerSettings::<F>::default();
285 quadratic_unconstrained_fb(mA, g, λ, x, τ, ins.iterator_options) 287 quadratic_unconstrained_fb(mA, g, λ, x, inner_τ, ins.iterator_options)
286 }) 288 }),
289 InnerMethod::PDPS => unimplemented!(),
287 } 290 }
288 } 291 }

mercurial