11#include <Eigen/SparseCore>
12#include <gch/small_vector.hpp>
14#include "sleipnir/autodiff/expression_type.hpp"
15#include "sleipnir/autodiff/variable.hpp"
16#include "sleipnir/util/assert.hpp"
25template <
typename Scalar>
31 gch::small_vector<std::pair<Scalar, Scalar>>
bounds;
35 gch::small_vector<std::pair<Eigen::Index, Eigen::Index>>
52template <
typename Scalar>
55 const Eigen::SparseMatrix<Scalar>& A_i) {
72 for (
int col = 0; col < A_i.outerSize(); ++col) {
73 for (
typename Eigen::SparseMatrix<Scalar>::InnerIterator
it{A_i, col};
it;
84 constexpr Eigen::Index NO_BOUND = -1;
85 gch::small_vector<std::pair<Eigen::Index, Eigen::Index>>
86 decision_var_indices_to_constraint_indices{decision_variables.size(),
87 {NO_BOUND, NO_BOUND}};
90 gch::small_vector<std::pair<Eigen::Index, Eigen::Index>>
91 conflicting_bound_indices;
94 gch::small_vector<std::pair<Scalar, Scalar>> decision_var_indices_to_bounds{
95 decision_variables.size(),
96 {-std::numeric_limits<Scalar>::infinity(),
97 std::numeric_limits<Scalar>::infinity()}};
101 Eigen::ArrayX<bool> bound_constraint_mask{inequality_constraints.size()};
102 bound_constraint_mask.fill(
false);
104 for (
typename decltype(inequality_constraints)::size_type constraint_index =
106 constraint_index < inequality_constraints.size(); ++constraint_index) {
109 if (inequality_constraints[constraint_index].type() !=
110 ExpressionType::LINEAR) {
113 if (row_num_nonzeros[constraint_index] != 1) {
132 const auto constraint_coefficient = row_nonzero_value[constraint_index];
137 if (constraint_coefficient == Scalar(0)) {
141 const auto decision_variable_index = row_nonzero_col[constraint_index];
142 const auto decision_variable_value =
143 decision_variables[decision_variable_index].value();
144 Scalar constraint_constant;
146 if (decision_variable_value != Scalar(0)) {
147 decision_variables[decision_variable_index].set_value(Scalar(0));
148 constraint_constant = inequality_constraints[constraint_index].value();
149 decision_variables[decision_variable_index].set_value(
150 decision_variable_value);
152 constraint_constant = inequality_constraints[constraint_index].value();
160 if (!isfinite(constraint_constant) || !isfinite(constraint_coefficient)) {
165 auto& [lower_bound, upper_bound] =
166 decision_var_indices_to_bounds[decision_variable_index];
167 auto& [lower_index, upper_index] =
168 decision_var_indices_to_constraint_indices[decision_variable_index];
169 const auto detected_bound = -constraint_constant / constraint_coefficient;
170 if (constraint_coefficient < Scalar(0) && detected_bound < upper_bound) {
171 upper_bound = detected_bound;
172 upper_index = constraint_index;
173 }
else if (constraint_coefficient > Scalar(0) &&
174 detected_bound > lower_bound) {
175 lower_bound = detected_bound;
176 lower_index = constraint_index;
180 if (lower_bound > upper_bound) {
181 conflicting_bound_indices.emplace_back(lower_index, upper_index);
185 bound_constraint_mask[constraint_index] =
true;
187 return {bound_constraint_mask, decision_var_indices_to_bounds,
188 conflicting_bound_indices};
203template <
typename Derived>
204 requires(
static_cast<bool>(Eigen::DenseBase<Derived>::IsVectorAtCompileTime))
205void project_onto_bounds(
206 Eigen::DenseBase<Derived>& x,
207 std::span<
const std::pair<
typename Eigen::DenseBase<Derived>::Scalar,
208 typename Eigen::DenseBase<Derived>::Scalar>>
209 decision_variable_indices_to_bounds,
210 const typename Eigen::DenseBase<Derived>::Scalar κ_1 =
211 typename Eigen::DenseBase<Derived>::Scalar(1e-2),
212 const typename Eigen::DenseBase<Derived>::Scalar κ_2 =
213 typename Eigen::DenseBase<Derived>::Scalar(1e-2)) {
214 using Scalar =
typename Eigen::DenseBase<Derived>::Scalar;
219 slp_assert(κ_1 > Scalar(0) && κ_2 > Scalar(0) && κ_2 < Scalar(0.5));
221 Eigen::Index decision_variable_idx = 0;
222 for (
const auto& [lower, upper] : decision_variable_indices_to_bounds) {
223 Scalar& x_i = x[decision_variable_idx++];
226 slp_assert(lower <= upper);
229 if (isfinite(lower) && isfinite(upper)) {
230 auto p_L = std::min(κ_1 * std::max(Scalar(1), abs(lower)),
231 κ_2 * (upper - lower));
232 auto p_U = std::min(κ_1 * std::max(Scalar(1), abs(upper)),
233 κ_2 * (upper - lower));
234 x_i = std::min(std::max(lower + p_L, x_i), upper - p_U);
235 }
else if (isfinite(lower)) {
236 x_i = std::max(x_i, lower + κ_1 * std::max(Scalar(1), abs(lower)));
237 }
else if (isfinite(upper)) {
238 x_i = std::min(x_i, upper - κ_1 * std::max(Scalar(1), abs(upper)));
Definition intrusive_shared_ptr.hpp:27
gch::small_vector< std::pair< Scalar, Scalar > > bounds
The tightest bounds on each decision variable.
Definition bounds.hpp:31
gch::small_vector< std::pair< Eigen::Index, Eigen::Index > > conflicting_bound_indices
Definition bounds.hpp:36
Eigen::ArrayX< bool > bound_constraint_mask
Which constraints, if any, are bound constraints.
Definition bounds.hpp:28