alpaqa 1.0.0a14
Nonconvex constrained optimization
Loading...
Searching...
No Matches
box-constr-problem.hpp
Go to the documentation of this file.
1#pragma once
2
5
6#include <utility>
7
8namespace alpaqa {
9
10/// Implements common problem functions for minimization problems with box
11/// constraints. Meant to be used as a base class for custom problem
12/// implementations.
13/// Supports optional @f$ \ell_1 @f$-regularization.
14/// @ingroup grp_Problems
15template <Config Conf>
17 public:
20
21 /// Number of decision variables, dimension of x
23 /// Number of constraints, dimension of g(x) and z
25
26 /// Create a problem with inactive boxes @f$ (-\infty, +\infty) @f$, with
27 /// no @f$ \ell_1 @f$-regularization, and all general constraints handled
28 /// using ALM.
29 BoxConstrProblem(length_t n, ///< Number of decision variables
30 length_t m) ///< Number of constraints
31 : n{n}, m{m} {}
32
34 : n{C.lowerbound.size()}, m{D.lowerbound.size()}, C{std::move(C)}, D{std::move(D)},
36
37 /// Change the dimensions of the problem (number of decision variables and
38 /// number of constaints).
39 /// Destructive: resizes and/or resets the members @ref C, @ref D,
40 /// @ref l1_reg and @ref penalty_alm_split.
42 if (std::exchange(this->n, n) != n) {
43 C = Box{n};
44 if (l1_reg.size() > 1)
45 l1_reg.resize(0);
46 }
47 if (std::exchange(this->m, m) != m) {
48 D = Box{m};
50 }
51 }
52
57
58 /// Constraints of the decision variables, @f$ x \in C @f$
59 Box C{this->n};
60 /// Other constraints, @f$ g(x) \in D @f$
61 Box D{this->m};
62 /// @f$ \ell_1 @f$ (1-norm) regularization parameter.
63 /// Possible dimensions are: @f$ 0 @f$ (no regularization), @f$ 1 @f$ (a
64 /// single scalar factor), or @f$ n @f$ (a different factor for each
65 /// variable).
67
68 /// Components of the constraint function with indices below this number are
69 /// handled using a quadratic penalty method rather than using an
70 /// augmented Lagrangian method. Specifically, the Lagrange multipliers for
71 /// these components (which determine the shifts in ALM) are kept at zero.
73
74 /// Number of decision variables, @ref n
75 length_t get_n() const { return n; }
76 /// Number of constraints, @ref m
77 length_t get_m() const { return m; }
78
79 /** Projected gradient step for rectangular box C.
80 * @f[ \begin{aligned} \hat x &= \Pi_C(x - \gamma\nabla\psi(x)) \\
81 * p &= \hat x - x \\
82 * &= \max(\underline x - x, \;\min(-\gamma\nabla\psi(x), \overline x - x)
83 * \end{aligned} @f] */
84 static real_t eval_proj_grad_step_box(const Box &C, real_t γ, crvec x, crvec grad_ψ, rvec x̂,
85 rvec p) {
86 p = (-γ * grad_ψ).cwiseMax(C.lowerbound - x).cwiseMin(C.upperbound - x);
87 x̂ = x + p;
88 return real_t(0);
89 }
90
91 /** Proximal gradient step for rectangular box C with ℓ₁-regularization.
92 * @f[ \begin{aligned} h(x) &= \|x\|_1 + \delta_C(x) \\
93 * \hat x &= \prox_{\gamma h}(x - \gamma\nabla\psi(x)) \\
94 * &= -\max\big(
95 * x - \overline x,
96 * \;\min\big(
97 * x - \underline x,
98 * \;\min\big(
99 * \gamma(\nabla\psi(x) + \lambda),
100 * \;\max\big(
101 * \gamma(\nabla\psi(x) - \lambda),
102 * x
103 * \big)
104 * \big)
105 * \big)
106 * \big) \end{aligned} @f] */
107 static void eval_prox_grad_step_box_l1_impl(const Box &C, const auto &λ, real_t γ, crvec x,
108 crvec grad_ψ, rvec x̂, rvec p) {
109 p = -x.cwiseMax(γ * (grad_ψ - λ))
110 .cwiseMin(γ * (grad_ψ + λ))
111 .cwiseMin(x - C.lowerbound)
112 .cwiseMax(x - C.upperbound);
113 x̂ = x + p;
114 }
115 /// @copydoc eval_prox_grad_step_box_l1_impl
116 static real_t eval_prox_grad_step_box_l1(const Box &C, const auto &λ, real_t γ, crvec x,
117 crvec grad_ψ, rvec x̂, rvec p) {
118 eval_prox_grad_step_box_l1_impl(C, λ, γ, x, grad_ψ, x̂, p);
119 return vec_util::norm_1(x̂.cwiseProduct(λ));
120 }
121
122 /// @copydoc eval_prox_grad_step_box_l1_impl
124 crvec grad_ψ, rvec x̂, rvec p) {
125 auto n = x.size();
126 auto λ_vec = vec::Constant(n, λ);
127 eval_prox_grad_step_box_l1_impl(C, λ_vec, γ, x, grad_ψ, x̂, p);
128 return λ * vec_util ::norm_1(x̂);
129 }
130
131 /// @see @ref TypeErasedProblem::eval_prox_grad_step
132 real_t eval_prox_grad_step(real_t γ, crvec x, crvec grad_ψ, rvec x̂, rvec p) const {
133 if (l1_reg.size() == 0)
134 return eval_proj_grad_step_box(C, γ, x, grad_ψ, x̂, p);
135 else if (l1_reg.size() == 1)
136 return eval_prox_grad_step_box_l1_scal(C, l1_reg(0), γ, x, grad_ψ, x̂, p);
137 else
138 return eval_prox_grad_step_box_l1(C, l1_reg, γ, x, grad_ψ, x̂, p);
139 }
140
141 /// @see @ref TypeErasedProblem::eval_proj_diff_g
142 void eval_proj_diff_g(crvec z, rvec p) const { p = projecting_difference(z, D); }
143
144 static void eval_proj_multipliers_box(const Box &D, rvec y, real_t M,
146 // If there's no lower bound, the multipliers can only be positive
147 auto max_lb = [M](real_t y, real_t z_lb) {
149 return std::max(y, y_lb);
150 };
151 // If there's no upper bound, the multipliers can only be negative
152 auto min_ub = [M](real_t y, real_t z_ub) {
154 return std::min(y, y_ub);
155 };
156 auto num_alm = y.size() - penalty_alm_split;
157 auto &&y_qpm = y.topRows(penalty_alm_split);
158 auto &&y_alm = y.bottomRows(num_alm);
159 auto &&z_alm_lb = D.lowerbound.bottomRows(num_alm);
160 auto &&z_alm_ub = D.upperbound.bottomRows(num_alm);
161 y_qpm.setZero();
162 y_alm = y_alm.binaryExpr(z_alm_lb, max_lb).binaryExpr(z_alm_ub, min_ub);
163 }
164
165 /// @see @ref TypeErasedProblem::eval_proj_multipliers
169
170 /// @see @ref TypeErasedProblem::get_box_C
171 const Box &get_box_C() const { return C; }
172 /// @see @ref TypeErasedProblem::get_box_D
173 const Box &get_box_D() const { return D; }
174
175 /// @see @ref TypeErasedProblem::eval_inactive_indices_res_lna
177 index_t nJ = 0;
178 // Helper that adds i to index set J if x ∊ C
179 const auto add_to_J_if_in_box_interior = [&](real_t x_fw, index_t i) {
180 if (C.lowerbound(i) < x_fw && x_fw < C.upperbound(i))
181 J(nJ++) = i;
182 };
183 // Update the index set J for the general box + l1 case
184 const auto update_J_general = [&](real_t λ, real_t x_fw, index_t i) {
185 if (λ == 0) {
187 } else {
188 if (x_fw > γ * λ)
189 add_to_J_if_in_box_interior(x_fw - γ * λ, i);
190 else if (x_fw < -γ * λ)
191 add_to_J_if_in_box_interior(x_fw + γ * λ, i);
192 }
193 };
194 const auto = l1_reg.size();
195 const bool λ_is_0 = == 0 || ( == 1 && l1_reg(0) == 0);
196 // Only box constraints
197 if (λ_is_0)
198 for (index_t i = 0; i < n; ++i) {
199 real_t x_fw = x(i) - γ * grad_ψ(i);
201 }
202 // Box constraints and l1
203 else
204 for (index_t i = 0; i < n; ++i) {
205 real_t λi = == 0 ? 0 : == 1 ? l1_reg(0) : l1_reg(i);
206 real_t x_fw = x(i) - γ * grad_ψ(i);
208 }
209 return nJ;
210 }
211
212 /// @see @ref TypeErasedProblem::check
213 void check() const {
215 "Length of problem.C.lowerbound does not match problem size problem.n");
217 "Length of problem.C.upperbound does not match problem size problem.n");
219 "Length of problem.D.lowerbound does not match problem size problem.m");
221 "Length of problem.D.upperbound does not match problem size problem.m");
222 if (l1_reg.size() > 1)
224 l1_reg, n,
225 "Length of problem.l1_reg does not match problem size problem.n, 1 or 0");
227 throw std::invalid_argument("Invalid penalty_alm_split");
228 }
229};
230
231} // namespace alpaqa
Implements common problem functions for minimization problems with box constraints.
Box C
Constraints of the decision variables, .
index_t eval_inactive_indices_res_lna(real_t γ, crvec x, crvec grad_ψ, rindexvec J) const
void eval_proj_diff_g(crvec z, rvec p) const
static real_t eval_prox_grad_step_box_l1(const Box &C, const auto &λ, real_t γ, crvec x, crvec grad_ψ, rvec x̂, rvec p)
Proximal gradient step for rectangular box C with ℓ₁-regularization.
static void eval_proj_multipliers_box(const Box &D, rvec y, real_t M, index_t penalty_alm_split)
BoxConstrProblem(const BoxConstrProblem &)=default
length_t m
Number of constraints, dimension of g(x) and z.
static void eval_prox_grad_step_box_l1_impl(const Box &C, const auto &λ, real_t γ, crvec x, crvec grad_ψ, rvec x̂, rvec p)
Proximal gradient step for rectangular box C with ℓ₁-regularization.
BoxConstrProblem & operator=(const BoxConstrProblem &)=default
length_t get_m() const
Number of constraints, m.
index_t penalty_alm_split
Components of the constraint function with indices below this number are handled using a quadratic pe...
length_t n
Number of decision variables, dimension of x.
BoxConstrProblem(Box C, Box D, vec l1_reg=vec(0), index_t penalty_alm_split=0)
Box D
Other constraints, .
void eval_proj_multipliers(rvec y, real_t M) const
BoxConstrProblem(BoxConstrProblem &&) noexcept=default
real_t eval_prox_grad_step(real_t γ, crvec x, crvec grad_ψ, rvec x̂, rvec p) const
void resize(length_t n, length_t m)
Change the dimensions of the problem (number of decision variables and number of constaints).
BoxConstrProblem(length_t n, length_t m)
Create a problem with inactive boxes , with no -regularization, and all general constraints handled u...
static real_t eval_prox_grad_step_box_l1_scal(const Box &C, real_t λ, real_t γ, crvec x, crvec grad_ψ, rvec x̂, rvec p)
Proximal gradient step for rectangular box C with ℓ₁-regularization.
length_t get_n() const
Number of decision variables, n.
vec l1_reg
(1-norm) regularization parameter.
static real_t eval_proj_grad_step_box(const Box &C, real_t γ, crvec x, crvec grad_ψ, rvec x̂, rvec p)
Projected gradient step for rectangular box C.
#define USING_ALPAQA_CONFIG(Conf)
Definition config.hpp:56
void check_dim_msg(const V &v, auto sz, std::string msg)
Definition check-dim.hpp:11
auto norm_1(const Eigen::MatrixBase< Derived > &v)
Get the 1-norm of the given vector.
Definition config.hpp:171
typename Conf::real_t real_t
Definition config.hpp:65
typename Conf::rindexvec rindexvec
Definition config.hpp:79
typename Conf::index_t index_t
Definition config.hpp:77
typename Conf::length_t length_t
Definition config.hpp:76
constexpr const auto inf
Definition config.hpp:85
typename Conf::rvec rvec
Definition config.hpp:69
typename Conf::crvec crvec
Definition config.hpp:70
typename Conf::vec vec
Definition config.hpp:66