58 const Eigen::SparseMatrix<Scalar, Eigen::RowMajor>& A_i) {
68 slp_assert(
static_cast<Eigen::Index
>(decision_variables.size()) ==
70 slp_assert(
static_cast<Eigen::Index
>(inequality_constraints.size()) ==
76 constexpr Eigen::Index NO_BOUND = -1;
78 decision_var_indices_to_constraint_indices{decision_variables.size(),
79 {NO_BOUND, NO_BOUND}};
83 conflicting_bound_indices;
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() !=
105 const Eigen::SparseVector<Scalar>& row_A_i =
106 A_i.innerVector(constraint_index);
107 const auto non_zeros = row_A_i.nonZeros();
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));
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};
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++];
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)));
void project_onto_bounds(Eigen::DenseBase< Derived > &x, std::span< const std::pair< typename Eigen::DenseBase< Derived >::Scalar, typename Eigen::DenseBase< Derived >::Scalar > > decision_variable_indices_to_bounds, const typename Eigen::DenseBase< Derived >::Scalar κ_1=typename Eigen::DenseBase< Derived >::Scalar(1e-2), const typename Eigen::DenseBase< Derived >::Scalar κ_2=typename Eigen::DenseBase< Derived >::Scalar(1e-2))
Projects the decision variables onto the given bounds, while ensuring some configurable distance from...
Definition bounds.hpp:195
Bounds< Scalar > get_bounds(std::span< Variable< Scalar > > decision_variables, std::span< Variable< Scalar > > inequality_constraints, const Eigen::SparseMatrix< Scalar, Eigen::RowMajor > &A_i)
A "bound constraint" is any linear constraint in one scalar variable.
Definition bounds.hpp:55