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