60 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
95 EIGEN_MAKE_ALIGNED_OPERATOR_NEW
106 throw std::runtime_error(
"var_dim must be positive: " + std::to_string(
var_dim_) +
" <= 0");
110 if constexpr(VarDim != Eigen::Dynamic)
114 throw std::runtime_error(
"var_dim is inconsistent with template parameter: " + std::to_string(
var_dim_)
115 +
" != " + std::to_string(VarDim));
131 return solve(H, g, lower, upper, VarDimVector::Zero(
var_dim_));
148 VarDimVector x = initial_x.cwiseMin(upper).cwiseMax(lower);
149 double obj = x.dot(g) + 0.5 * x.dot(H * x);
150 double old_obj = obj;
155 initial_trace_data.
iter = 0;
156 initial_trace_data.
x = x;
157 initial_trace_data.
obj = obj;
162 int factorization_num = 0;
173 trace_data.iter = iter;
187 old_clamped_flag = clamped_flag;
188 clamped_flag.setConstant(
false);
190 ((x.array() == lower.array() && grad.array() > 0) || (x.array() == upper.array() && grad.array() < 0))
191 .select(
true, clamped_flag);
194 std::vector<int> clamped_idxs;
196 for(
int i = 0; i < clamped_flag.size(); i++)
200 clamped_idxs.push_back(i);
209 if(clamped_flag.all())
216 if(iter == 1 || (clamped_flag != old_clamped_flag).any())
229 llt_free_ = std::make_unique<Eigen::LLT<Eigen::MatrixXd>>(H_free);
230 if(
llt_free_->info() == Eigen::NumericalIssue)
234 std::cout <<
"[BoxQP] H_free is not positive definite in Cholesky decomposition (LLT)." << std::endl;
244 double grad_norm = 0;
247 grad_norm += std::pow(grad[
free_idxs_[i]], 2);
256 Eigen::VectorXd x_clamped(clamped_idxs.size());
259 Eigen::MatrixXd H_free_clamped(
free_idxs_.size(), clamped_idxs.size());
260 for(
size_t i = 0; i < clamped_idxs.size(); i++)
262 x_clamped[i] = x[clamped_idxs[i]];
268 for(
size_t j = 0; j < clamped_idxs.size(); j++)
270 H_free_clamped(i, j) = H(
free_idxs_[i], clamped_idxs[j]);
273 Eigen::VectorXd grad_free_clamped = g_free + H_free_clamped * x_clamped;
274 Eigen::VectorXd search_dir_free = -1 *
llt_free_->solve(grad_free_clamped) - x_free;
278 search_dir[
free_idxs_[i]] = search_dir_free[i];
282 double search_dir_grad = search_dir.dot(grad);
283 if(search_dir_grad > 1e-10)
287 std::cout <<
"[BoxQP] search_dir_grad is positive: " << search_dir_grad << std::endl;
296 VarDimVector x_candidate = (x + step * search_dir).cwiseMin(upper).cwiseMax(lower);
297 double obj_candidate = x_candidate.dot(g) + 0.5 * x_candidate.dot(H * x_candidate);
302 x_candidate = (x + step * search_dir).cwiseMin(upper).cwiseMax(lower);
303 obj_candidate = x_candidate.dot(g) + 0.5 * x_candidate.dot(H * x_candidate);
314 std::cout <<
"[BoxQP] iter: " << iter <<
", obj: " << obj <<
", grad_norm: " << grad_norm
315 <<
", obj_update, : " << old_obj - obj_candidate <<
", step: " << step
316 <<
", clamped_flag_num: " << clamped_idxs.size() << std::endl;
321 trace_data.obj = obj;
322 trace_data.search_dir = search_dir;
323 trace_data.clamped_flag = clamped_flag;
324 trace_data.factorization_num = factorization_num;
325 trace_data.step_num = step_num;
343 <<
", obj: " << obj <<
", factorization_num: " << factorization_num << std::endl;
375 const std::unordered_map<int, std::string>
retstr_ = {{-2,
"Gradient of search direction is positive"},
376 {-1,
"Hessian is not positive definite"},
377 {0,
"Computation is not finished"},
378 {1,
"Maximum main iterations exceeded"},
379 {2,
"Maximum line-search iterations exceeded"},
380 {3,
"No bounds, returning Newton point"},
381 {4,
"Improvement smaller than tolerance"},
382 {5,
"Gradient norm smaller than tolerance"},
383 {6,
"All dimensions are clamped"}};