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"
27template <
typename Scalar>
33 gch::small_vector<std::pair<Scalar, Scalar>>
bounds;
37 gch::small_vector<std::pair<Eigen::Index, Eigen::Index>>
58template <
typename Scalar>
62 const Eigen::SparseMatrix<Scalar, Eigen::RowMajor>& A_i) {
80 constexpr Eigen::Index
NO_BOUND = -1;
81 gch::small_vector<std::pair<Eigen::Index, Eigen::Index>>
86 gch::small_vector<std::pair<Eigen::Index, Eigen::Index>>
87 conflicting_bound_indices;
90 gch::small_vector<std::pair<Scalar, Scalar>> decision_var_indices_to_bounds{
91 decision_variables.size(),
92 {-std::numeric_limits<Scalar>::infinity(),
93 std::numeric_limits<Scalar>::infinity()}};
97 Eigen::ArrayX<bool> bound_constraint_mask{inequality_constraints.size()};
98 bound_constraint_mask.fill(
false);
100 for (
typename decltype(inequality_constraints)::size_type constraint_index =
102 constraint_index < inequality_constraints.size(); ++constraint_index) {
105 if (inequality_constraints[constraint_index].type() !=
106 ExpressionType::LINEAR) {
109 const Eigen::SparseVector<Scalar>& row_A_i =
110 A_i.innerVector(constraint_index);
111 const auto non_zeros = row_A_i.nonZeros();
112 slp_assert(non_zeros != 0);
126 typename Eigen::SparseVector<Scalar>::InnerIterator row_iter(row_A_i);
127 const auto constraint_coefficient =
130 const auto decision_variable_index = row_iter.index();
131 const auto decision_variable_value =
132 decision_variables[decision_variable_index].value();
133 Scalar constraint_constant;
135 if (decision_variable_value != Scalar(0)) {
136 decision_variables[decision_variable_index].set_value(Scalar(0));
137 constraint_constant = inequality_constraints[constraint_index].value();
138 decision_variables[decision_variable_index].set_value(
139 decision_variable_value);
141 constraint_constant = inequality_constraints[constraint_index].value();
146 slp_assert(constraint_coefficient != Scalar(0));
152 slp_assert(isfinite(constraint_constant));
156 slp_assert(isfinite(constraint_coefficient));
159 auto& [lower_bound, upper_bound] =
160 decision_var_indices_to_bounds[decision_variable_index];
161 auto& [lower_index, upper_index] =
162 decision_var_indices_to_constraint_indices[decision_variable_index];
163 const auto detected_bound = -constraint_constant / constraint_coefficient;
164 if (constraint_coefficient < Scalar(0) && detected_bound < upper_bound) {
165 upper_bound = detected_bound;
166 upper_index = constraint_index;
167 }
else if (constraint_coefficient > Scalar(0) &&
168 detected_bound > lower_bound) {
169 lower_bound = detected_bound;
170 lower_index = constraint_index;
174 if (lower_bound > upper_bound) {
175 conflicting_bound_indices.emplace_back(lower_index, upper_index);
179 bound_constraint_mask[constraint_index] =
true;
181 return {bound_constraint_mask, decision_var_indices_to_bounds,
182 conflicting_bound_indices};
199template <
typename Derived>
200 requires(
static_cast<bool>(Eigen::DenseBase<Derived>::IsVectorAtCompileTime))
201void project_onto_bounds(
202 Eigen::DenseBase<Derived>& x,
203 std::span<
const std::pair<
typename Eigen::DenseBase<Derived>::Scalar,
204 typename Eigen::DenseBase<Derived>::Scalar>>
205 decision_variable_indices_to_bounds,
206 const typename Eigen::DenseBase<Derived>::Scalar κ_1 =
207 typename Eigen::DenseBase<Derived>::Scalar(1e-2),
208 const typename Eigen::DenseBase<Derived>::Scalar κ_2 =
209 typename Eigen::DenseBase<Derived>::Scalar(1e-2)) {
210 using Scalar =
typename Eigen::DenseBase<Derived>::Scalar;
215 slp_assert(κ_1 > Scalar(0) && κ_2 > Scalar(0) && κ_2 < Scalar(0.5));
217 Eigen::Index decision_variable_idx = 0;
218 for (
const auto& [lower, upper] : decision_variable_indices_to_bounds) {
219 Scalar& x_i = x[decision_variable_idx++];
222 slp_assert(lower <= upper);
225 if (isfinite(lower) && isfinite(upper)) {
226 auto p_L = std::min(κ_1 * std::max(Scalar(1), abs(lower)),
227 κ_2 * (upper - lower));
228 auto p_U = std::min(κ_1 * std::max(Scalar(1), abs(upper)),
229 κ_2 * (upper - lower));
230 x_i = std::min(std::max(lower + p_L, x_i), upper - p_U);
231 }
else if (isfinite(lower)) {
232 x_i = std::max(x_i, lower + κ_1 * std::max(Scalar(1), abs(lower)));
233 }
else if (isfinite(upper)) {
234 x_i = std::min(x_i, upper - κ_1 * std::max(Scalar(1), abs(upper)));
Definition intrusive_shared_ptr.hpp:29
gch::small_vector< std::pair< Scalar, Scalar > > bounds
The tightest bounds on each decision variable.
Definition bounds.hpp:33
gch::small_vector< std::pair< Eigen::Index, Eigen::Index > > conflicting_bound_indices
Definition bounds.hpp:38
Eigen::ArrayX< bool > bound_constraint_mask
Which constraints, if any, are bound constraints.
Definition bounds.hpp:30