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>>
54template <
typename Scalar>
58 const Eigen::SparseMatrix<Scalar, Eigen::RowMajor>& A_i) {
76 constexpr Eigen::Index
NO_BOUND = -1;
77 gch::small_vector<std::pair<Eigen::Index, Eigen::Index>>
82 gch::small_vector<std::pair<Eigen::Index, Eigen::Index>>
83 conflicting_bound_indices;
86 gch::small_vector<std::pair<Scalar, Scalar>> decision_var_indices_to_bounds{
87 decision_variables.size(),
88 {-std::numeric_limits<Scalar>::infinity(),
89 std::numeric_limits<Scalar>::infinity()}};
93 Eigen::ArrayX<bool> bound_constraint_mask{inequality_constraints.size()};
94 bound_constraint_mask.fill(
false);
96 for (
typename decltype(inequality_constraints)::size_type constraint_index =
98 constraint_index < inequality_constraints.size(); ++constraint_index) {
101 if (inequality_constraints[constraint_index].type() !=
102 ExpressionType::LINEAR) {
105 const Eigen::SparseVector<Scalar>& row_A_i =
106 A_i.innerVector(constraint_index);
107 const auto non_zeros = row_A_i.nonZeros();
108 slp_assert(non_zeros != 0);
122 typename Eigen::SparseVector<Scalar>::InnerIterator row_iter(row_A_i);
123 const auto constraint_coefficient =
126 const auto decision_variable_index = row_iter.index();
127 const auto decision_variable_value =
128 decision_variables[decision_variable_index].value();
129 Scalar constraint_constant;
131 if (decision_variable_value != Scalar(0)) {
132 decision_variables[decision_variable_index].set_value(Scalar(0));
133 constraint_constant = inequality_constraints[constraint_index].value();
134 decision_variables[decision_variable_index].set_value(
135 decision_variable_value);
137 constraint_constant = inequality_constraints[constraint_index].value();
142 slp_assert(constraint_coefficient != Scalar(0));
148 slp_assert(isfinite(constraint_constant));
152 slp_assert(isfinite(constraint_coefficient));
155 auto& [lower_bound, upper_bound] =
156 decision_var_indices_to_bounds[decision_variable_index];
157 auto& [lower_index, upper_index] =
158 decision_var_indices_to_constraint_indices[decision_variable_index];
159 const auto detected_bound = -constraint_constant / constraint_coefficient;
160 if (constraint_coefficient < Scalar(0) && detected_bound < upper_bound) {
161 upper_bound = detected_bound;
162 upper_index = constraint_index;
163 }
else if (constraint_coefficient > Scalar(0) &&
164 detected_bound > lower_bound) {
165 lower_bound = detected_bound;
166 lower_index = constraint_index;
170 if (lower_bound > upper_bound) {
171 conflicting_bound_indices.emplace_back(lower_index, upper_index);
175 bound_constraint_mask[constraint_index] =
true;
177 return {bound_constraint_mask, decision_var_indices_to_bounds,
178 conflicting_bound_indices};
193template <
typename Derived>
194 requires(
static_cast<bool>(Eigen::DenseBase<Derived>::IsVectorAtCompileTime))
195void project_onto_bounds(
196 Eigen::DenseBase<Derived>& x,
197 std::span<
const std::pair<
typename Eigen::DenseBase<Derived>::Scalar,
198 typename Eigen::DenseBase<Derived>::Scalar>>
199 decision_variable_indices_to_bounds,
200 const typename Eigen::DenseBase<Derived>::Scalar κ_1 =
201 typename Eigen::DenseBase<Derived>::Scalar(1e-2),
202 const typename Eigen::DenseBase<Derived>::Scalar κ_2 =
203 typename Eigen::DenseBase<Derived>::Scalar(1e-2)) {
204 using Scalar =
typename Eigen::DenseBase<Derived>::Scalar;
209 slp_assert(κ_1 > Scalar(0) && κ_2 > Scalar(0) && κ_2 < Scalar(0.5));
211 Eigen::Index decision_variable_idx = 0;
212 for (
const auto& [lower, upper] : decision_variable_indices_to_bounds) {
213 Scalar& x_i = x[decision_variable_idx++];
216 slp_assert(lower <= upper);
219 if (isfinite(lower) && isfinite(upper)) {
220 auto p_L = std::min(κ_1 * std::max(Scalar(1), abs(lower)),
221 κ_2 * (upper - lower));
222 auto p_U = std::min(κ_1 * std::max(Scalar(1), abs(upper)),
223 κ_2 * (upper - lower));
224 x_i = std::min(std::max(lower + p_L, x_i), upper - p_U);
225 }
else if (isfinite(lower)) {
226 x_i = std::max(x_i, lower + κ_1 * std::max(Scalar(1), abs(lower)));
227 }
else if (isfinite(upper)) {
228 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