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"}};
Solver for quadratic programming problems with box constraints (i.e., only upper and lower bounds).
VarDimVector solve(const VarVarDimMatrix &H, const VarDimVector &g, const VarDimVector &lower, const VarDimVector &upper, const VarDimVector &initial_x)
Solve optimization.
std::unique_ptr< Eigen::LLT< Eigen::MatrixXd > > llt_free_
Cholesky decomposition (LLT) of free block of objective Hessian matrix.
const std::unordered_map< int, std::string > retstr_
Return string.
EIGEN_MAKE_ALIGNED_OPERATOR_NEW BoxQP(int var_dim=VarDim)
Constructor.
Configuration config_
Configuration.
std::vector< int > free_idxs_
Indices of free dimensions in decision variables.
Configuration & config()
Accessor to configuration.
const Configuration & config() const
Const accessor to configuration.
const int var_dim_
Dimension of decision variables.
Eigen::Matrix< double, VarDim, 1 > VarDimVector
Type of vector of variables dimension.
Eigen::Matrix< double, VarDim, VarDim > VarVarDimMatrix
Type of matrix of variables x variables dimension.
Eigen::Array< bool, VarDim, 1 > VarDimArray
Type of boolean array of variables dimension.
std::vector< TraceData > trace_data_list_
Sequence of trace data.
VarDimVector solve(const VarVarDimMatrix &H, const VarDimVector &g, const VarDimVector &lower, const VarDimVector &upper)
Solve optimization.
const std::vector< TraceData > & traceDataList() const
Const accessor to trace data list.
double min_step
Minimum stepsize for linesearch.
double grad_thre
Termination threshold of non-fixed gradient.
double armijo_param
Armijo parameter (fraction of linear improvement required)
int print_level
Print level (0: no print, 1: print only important, 2: print verbose, 3: print very verbose)
double rel_improve_thre
Termination threshold of relative improvement.
int max_iter
Maximum iteration of optimization loop.
double step_factor
Factor for decreasing stepsize.
Data to trace optimization loop.
EIGEN_MAKE_ALIGNED_OPERATOR_NEW int iter
Iteration of optimization loop.
int factorization_num
Number of factorization.
VarDimVector search_dir
Search direction.
VarDimVector x
Decision variables.
VarDimArray clamped_flag
Flag of clamped variables dimensions.
double obj
Objective value.
TraceData(int var_dim)
Constructor.
int step_num
Number of linesearch step.