18 const double th_acceptstep,
const double th_grad,
const double reg)
21 th_acceptstep_(th_acceptstep),
35 if (0. >= th_acceptstep && th_acceptstep >= 0.5) {
36 std::cerr <<
"Warning: th_acceptstep value should between 0 and 0.5"
40 std::cerr <<
"Warning: th_grad value has to be positive." << std::endl;
43 std::cerr <<
"Warning: reg value has to be positive." << std::endl;
57 solution_.
x = Eigen::VectorXd::Zero(nx);
60 const std::size_t n_alphas_ = 10;
61 alphas_.resize(n_alphas_);
62 for (std::size_t n = 0; n < n_alphas_; ++n) {
63 alphas_[n] = 1. / pow(2.,
static_cast<double>(n));
70 const Eigen::VectorXd& q,
71 const Eigen::VectorXd& lb,
72 const Eigen::VectorXd& ub,
73 const Eigen::VectorXd& xinit) {
74 if (
static_cast<std::size_t
>(H.rows()) != nx_ ||
75 static_cast<std::size_t
>(H.cols()) != nx_) {
76 throw_pretty(
"Invalid argument: "
77 <<
"H has wrong dimension (it should be " +
78 std::to_string(nx_) +
"," + std::to_string(nx_) +
")");
80 if (
static_cast<std::size_t
>(q.size()) != nx_) {
82 "Invalid argument: " <<
"q has wrong dimension (it should be " +
83 std::to_string(nx_) +
")");
85 if (
static_cast<std::size_t
>(lb.size()) != nx_) {
87 "Invalid argument: " <<
"lb has wrong dimension (it should be " +
88 std::to_string(nx_) +
")");
90 if (
static_cast<std::size_t
>(ub.size()) != nx_) {
92 "Invalid argument: " <<
"ub has wrong dimension (it should be " +
93 std::to_string(nx_) +
")");
95 if (
static_cast<std::size_t
>(xinit.size()) != nx_) {
97 "Invalid argument: " <<
"xinit has wrong dimension (it should be " +
98 std::to_string(nx_) +
")");
102 for (std::size_t i = 0; i < nx_; ++i) {
103 x_(i) = std::max(std::min(xinit(i), ub(i)), lb(i));
107 for (std::size_t k = 0; k < maxiter_; ++k) {
112 g_.noalias() += H * x_;
113 for (std::size_t j = 0; j < nx_; ++j) {
114 const double gj = g_(j);
115 const double xj = x_(j);
116 const double lbj = lb(j);
117 const double ubj = ub(j);
118 if ((xj == lbj && gj > 0.) || (xj == ubj && gj < 0.)) {
128 Eigen::VectorBlock<Eigen::VectorXd> xf = xo_.head(nf_);
129 Eigen::VectorBlock<Eigen::VectorXd> xc = xo_.tail(nc_);
130 Eigen::VectorBlock<Eigen::VectorXd> dxf = dxo_.head(nf_);
131 Eigen::VectorBlock<Eigen::VectorXd> qf = qo_.head(nf_);
132 Eigen::Block<Eigen::MatrixXd> Hff = Ho_.topLeftCorner(nf_, nf_);
133 Eigen::Block<Eigen::MatrixXd> Hfc = Ho_.topRightCorner(nf_, nc_);
134 for (std::size_t i = 0; i < nf_; ++i) {
135 const std::size_t fi = solution_.
free_idx[i];
138 for (std::size_t j = 0; j < nf_; ++j) {
139 Hff(i, j) = H(fi, solution_.
free_idx[j]);
141 for (std::size_t j = 0; j < nc_; ++j) {
144 Hfc(i, j) = H(fi, cj);
148 Hff.diagonal().array() += reg_;
150 Hff_inv_llt_.compute(Hff);
151 const Eigen::ComputationInfo& info = Hff_inv_llt_.info();
152 if (info != Eigen::Success) {
153 throw_pretty(
"backward_error");
155 solution_.
Hff_inv.setIdentity(nf_, nf_);
156 Hff_inv_llt_.solveInPlace(solution_.
Hff_inv);
157 qf.noalias() += Hff * xf;
159 qf.noalias() += Hfc * xc;
162 Hff_inv_llt_.solveInPlace(dxf);
164 for (std::size_t i = 0; i < nf_; ++i) {
165 dx_(solution_.
free_idx[i]) = dxf(i);
170 fold_ = 0.5 * x_.dot(H * x_) + q.dot(x_);
171 for (std::vector<double>::const_iterator it = alphas_.begin();
172 it != alphas_.end(); ++it) {
173 double steplength = *it;
174 for (std::size_t i = 0; i < nx_; ++i) {
176 std::max(std::min(x_(i) + steplength * dx_(i), ub(i)), lb(i));
178 fnew_ = 0.5 * xnew_.dot(H * xnew_) + q.dot(xnew_);
179 if (fold_ - fnew_ > th_acceptstep_ * g_.dot(x_ - xnew_)) {
186 if (qf.lpNorm<Eigen::Infinity>() <= th_grad_) {
211 x_.conservativeResize(nx);
212 xnew_.conservativeResize(nx);
213 g_.conservativeResize(nx);
214 dx_.conservativeResize(nx);
215 xo_.conservativeResize(nx);
216 dxo_.conservativeResize(nx);
217 qo_.conservativeResize(nx);
218 Ho_.conservativeResize(nx, nx);
const BoxQPSolution & solve(const Eigen::MatrixXd &H, const Eigen::VectorXd &q, const Eigen::VectorXd &lb, const Eigen::VectorXd &ub, const Eigen::VectorXd &xinit)
Compute the solution of bound-constrained QP based on Newton projection.
EIGEN_MAKE_ALIGNED_OPERATOR_NEW BoxQP(const std::size_t nx, const std::size_t maxiter=100, const double th_acceptstep=0.1, const double th_grad=1e-9, const double reg=1e-9)
Initialize the Projected-Newton QP for bound constraints.