4#ifndef LBFGSPP_SUBSPACE_MIN_H
5#define LBFGSPP_SUBSPACE_MIN_H
33template <
typename Scalar>
37 using Vector = Eigen::Matrix<Scalar, Eigen::Dynamic, 1>;
38 using Matrix = Eigen::Matrix<Scalar, Eigen::Dynamic, Eigen::Dynamic>;
39 using IndexSet = std::vector<int>;
42 static Vector subvec(
const Vector& v,
const IndexSet& ind)
44 const int nsub = ind.size();
46 for (
int i = 0; i < nsub; i++)
52 static void subvec_assign(Vector& v,
const IndexSet& ind,
const Vector& rhs)
54 const int nsub = ind.size();
55 for (
int i = 0; i < nsub; i++)
60 static bool in_bounds(
const Vector& x,
const Vector& lb,
const Vector& ub)
62 const int n = x.size();
63 for (
int i = 0; i < n; i++)
65 if (x[i] < lb[i] || x[i] > ub[i])
72 static bool P_converged(
const IndexSet& yP_set,
const Vector& vecy,
const Vector& vecl,
const Vector& vecu)
74 const int nP = yP_set.size();
75 for (
int i = 0; i < nP; i++)
77 const int coord = yP_set[i];
78 if (vecy[coord] < vecl[coord] || vecy[coord] > vecu[coord])
85 static bool L_converged(
const IndexSet& yL_set,
const Vector& lambda)
87 const int nL = yL_set.size();
88 for (
int i = 0; i < nL; i++)
90 const int coord = yL_set[i];
91 if (lambda[coord] < Scalar(0))
98 static bool U_converged(
const IndexSet& yU_set,
const Vector& mu)
100 const int nU = yU_set.size();
101 for (
int i = 0; i < nU; i++)
103 const int coord = yU_set[i];
104 if (mu[coord] < Scalar(0))
122 static void subspace_minimize(
123 const BFGSMat<Scalar, true>& bfgs,
const Vector& x0,
const Vector& xcp,
const Vector& g,
124 const Vector& lb,
const Vector& ub,
const Vector& Wd,
const IndexSet& newact_set,
const IndexSet& fv_set,
int maxit,
130 drt.noalias() = xcp - x0;
132 const int nfree = fv_set.size();
144 Matrix WF = bfgs.Wb(fv_set);
147 bfgs.compute_FtBAb(WF, fv_set, newact_set, Wd, drt, vecc);
149 Vector vecl(nfree), vecu(nfree);
150 for (
int i = 0; i < nfree; i++)
152 const int coord = fv_set[i];
153 vecl[i] = lb[coord] - x0[coord];
154 vecu[i] = ub[coord] - x0[coord];
159 bfgs.solve_PtBP(WF, -vecc, vecy);
162 if (in_bounds(vecy, vecl, vecu))
164 subvec_assign(drt, fv_set, vecy);
170 Vector yfallback = vecy;
172 Vector lambda = Vector::Zero(nfree), mu = Vector::Zero(nfree);
175 IndexSet L_set, U_set, P_set, yL_set, yU_set, yP_set;
176 L_set.reserve(nfree / 3);
177 yL_set.reserve(nfree / 3);
178 U_set.reserve(nfree / 3);
179 yU_set.reserve(nfree / 3);
180 P_set.reserve(nfree);
181 yP_set.reserve(nfree);
183 for (k = 0; k < maxit; k++)
194 for (
int i = 0; i < nfree; i++)
196 const int coord = fv_set[i];
197 const Scalar li = vecl[i], ui = vecu[i];
198 if ((vecy[i] < li) || (vecy[i] == li && lambda[i] >= Scalar(0)))
200 L_set.push_back(coord);
205 else if ((vecy[i] > ui) || (vecy[i] == ui && mu[i] >= Scalar(0)))
207 U_set.push_back(coord);
210 lambda[i] = Scalar(0);
214 P_set.push_back(coord);
216 lambda[i] = Scalar(0);
227 Matrix WP = bfgs.Wb(P_set);
229 const int nP = P_set.size();
232 Vector rhs = subvec(vecc, yP_set);
233 Vector lL = subvec(vecl, yL_set);
234 Vector uU = subvec(vecu, yU_set);
236 bool nonzero = bfgs.apply_PtBQv(WP, L_set, lL, tmp,
true);
238 rhs.noalias() += tmp;
239 nonzero = bfgs.apply_PtBQv(WP, U_set, uU, tmp,
true);
241 rhs.noalias() += tmp;
243 bfgs.solve_PtBP(WP, -rhs, tmp);
244 subvec_assign(vecy, yP_set, tmp);
248 const int nL = L_set.size();
249 const int nU = U_set.size();
251 if (nL > 0 || nU > 0)
252 bfgs.apply_WtPv(fv_set, vecy, Fy);
256 bfgs.apply_PtWMv(L_set, Fy, res, Scalar(-1));
257 res.noalias() += subvec(vecc, yL_set) + bfgs.theta() * subvec(vecy, yL_set);
258 subvec_assign(lambda, yL_set, res);
265 bfgs.apply_PtWMv(U_set, Fy, negRes, Scalar(-1));
266 negRes.noalias() += subvec(vecc, yU_set) + bfgs.theta() * subvec(vecy, yU_set);
267 subvec_assign(mu, yU_set, -negRes);
271 if (L_converged(yL_set, lambda) && U_converged(yU_set, mu) && P_converged(yP_set, vecy, vecl, vecu))
278 vecy.noalias() = vecy.cwiseMax(vecl).cwiseMin(vecu);
279 subvec_assign(drt, fv_set, vecy);
281 Scalar dg = drt.dot(g);
283 if (dg <= -std::numeric_limits<Scalar>::epsilon())
287 vecy.noalias() = yfallback.cwiseMax(vecl).cwiseMin(vecu);
288 subvec_assign(drt, fv_set, vecy);
290 if (dg <= -std::numeric_limits<Scalar>::epsilon())
294 subvec_assign(drt, fv_set, yfallback);
301 subvec_assign(drt, fv_set, vecy);