Crocoddyl
 
Loading...
Searching...
No Matches
intro.cpp
1
2// BSD 3-Clause License
3//
4// Copyright (C) 2021-2023, Heriot-Watt University, University of Edinburgh
5// Copyright note valid unless otherwise stated in individual files.
6// All rights reserved.
8
9#include "crocoddyl/core/solvers/intro.hpp"
10
11#include <iostream>
12
13#include "crocoddyl/core/utils/exception.hpp"
14#include "crocoddyl/core/utils/stop-watch.hpp"
15
16namespace crocoddyl {
17
18SolverIntro::SolverIntro(std::shared_ptr<ShootingProblem> problem)
19 : SolverFDDP(problem),
20 eq_solver_(LuNull),
21 th_feas_(1e-4),
22 rho_(0.3),
23 upsilon_(0.),
24 zero_upsilon_(false) {
25 const std::size_t T = problem_->get_T();
26 Hu_rank_.resize(T);
27 KQuu_tmp_.resize(T);
28 YZ_.resize(T);
29 Hy_.resize(T);
30 Qz_.resize(T);
31 Qzz_.resize(T);
32 Qxz_.resize(T);
33 Quz_.resize(T);
34 kz_.resize(T);
35 Kz_.resize(T);
36 ks_.resize(T);
37 Ks_.resize(T);
38 QuuinvHuT_.resize(T);
39 Qzz_llt_.resize(T);
40 Hu_lu_.resize(T);
41 Hu_qr_.resize(T);
42 Hy_lu_.resize(T);
43
44 const std::size_t ndx = problem_->get_ndx();
45 const std::vector<std::shared_ptr<ActionModelAbstract> >& models =
46 problem_->get_runningModels();
47 for (std::size_t t = 0; t < T; ++t) {
48 const std::shared_ptr<ActionModelAbstract>& model = models[t];
49 const std::size_t nu = model->get_nu();
50 const std::size_t nh = model->get_nh();
51 Hu_rank_[t] = nh;
52 KQuu_tmp_[t] = Eigen::MatrixXd::Zero(ndx, nu);
53 YZ_[t] = Eigen::MatrixXd::Zero(nu, nu);
54 Hy_[t] = Eigen::MatrixXd::Zero(nh, nh);
55 Qz_[t] = Eigen::VectorXd::Zero(nh);
56 Qzz_[t] = Eigen::MatrixXd::Zero(nh, nh);
57 Qxz_[t] = Eigen::MatrixXd::Zero(ndx, nh);
58 Quz_[t] = Eigen::MatrixXd::Zero(nu, nh);
59 kz_[t] = Eigen::VectorXd::Zero(nu);
60 Kz_[t] = Eigen::MatrixXd::Zero(nu, ndx);
61 ks_[t] = Eigen::VectorXd::Zero(nh);
62 Ks_[t] = Eigen::MatrixXd::Zero(nh, ndx);
63 QuuinvHuT_[t] = Eigen::MatrixXd::Zero(nu, nh);
64 Qzz_llt_[t] = Eigen::LLT<Eigen::MatrixXd>(nh);
65 Hu_lu_[t] = Eigen::FullPivLU<Eigen::MatrixXd>(nh, nu);
66 Hu_qr_[t] = Eigen::ColPivHouseholderQR<Eigen::MatrixXd>(nu, nh);
67 Hy_lu_[t] = Eigen::PartialPivLU<Eigen::MatrixXd>(nh);
68 }
69}
70
71SolverIntro::~SolverIntro() {}
72
73bool SolverIntro::solve(const std::vector<Eigen::VectorXd>& init_xs,
74 const std::vector<Eigen::VectorXd>& init_us,
75 const std::size_t maxiter, const bool is_feasible,
76 const double init_reg) {
77 START_PROFILER("SolverIntro::solve");
78 if (problem_->is_updated()) {
79 resizeData();
80 }
81 xs_try_[0] =
82 problem_->get_x0(); // it is needed in case that init_xs[0] is infeasible
83 setCandidate(init_xs, init_us, is_feasible);
84
85 if (std::isnan(init_reg)) {
86 preg_ = reg_min_;
87 dreg_ = reg_min_;
88 } else {
89 preg_ = init_reg;
90 dreg_ = init_reg;
91 }
92 was_feasible_ = false;
93 if (zero_upsilon_) {
94 upsilon_ = 0.;
95 }
96
97 bool recalcDiff = true;
98 for (iter_ = 0; iter_ < maxiter; ++iter_) {
99 while (true) {
100 try {
101 computeDirection(recalcDiff);
102 } catch (std::exception& e) {
103 recalcDiff = false;
104 increaseRegularization();
105 if (preg_ == reg_max_) {
106 return false;
107 } else {
108 continue;
109 }
110 }
111 break;
112 }
115
116 // Update the penalty parameter for computing the merit function and its
117 // directional derivative For more details see Section 3 of "An Interior
118 // Point Algorithm for Large Scale Nonlinear Programming"
119 if (hfeas_ != 0 && iter_ != 0) {
120 upsilon_ =
121 std::max(upsilon_, (d_[0] + .5 * d_[1]) / ((1 - rho_) * hfeas_));
122 }
123
124 // We need to recalculate the derivatives when the step length passes
125 recalcDiff = false;
126 for (std::vector<double>::const_iterator it = alphas_.begin();
127 it != alphas_.end(); ++it) {
128 steplength_ = *it;
129 try {
130 dV_ = tryStep(steplength_);
131 dfeas_ = hfeas_ - hfeas_try_;
132 dPhi_ = dV_ + upsilon_ * dfeas_;
133 } catch (std::exception& e) {
134 continue;
135 }
137 dVexp_ = steplength_ * (d_[0] + 0.5 * steplength_ * d_[1]);
138 dPhiexp_ = dVexp_ + steplength_ * upsilon_ * dfeas_;
139 if (dPhiexp_ >= 0) { // descend direction
140 if (std::abs(d_[0]) < th_grad_ || dPhi_ > th_acceptstep_ * dPhiexp_) {
141 was_feasible_ = is_feasible_;
142 setCandidate(xs_try_, us_try_, (was_feasible_) || (steplength_ == 1));
143 cost_ = cost_try_;
144 hfeas_ = hfeas_try_;
145 merit_ = cost_ + upsilon_ * hfeas_;
146 recalcDiff = true;
147 break;
148 }
149 } else { // reducing the gaps by allowing a small increment in the cost
150 // value
151 if (dV_ > th_acceptnegstep_ * dVexp_) {
152 was_feasible_ = is_feasible_;
153 setCandidate(xs_try_, us_try_, (was_feasible_) || (steplength_ == 1));
154 cost_ = cost_try_;
155 hfeas_ = hfeas_try_;
156 merit_ = cost_ + upsilon_ * hfeas_;
157 recalcDiff = true;
158 break;
159 }
160 }
161 }
162
163 stoppingCriteria();
164 const std::size_t n_callbacks = callbacks_.size();
165 for (std::size_t c = 0; c < n_callbacks; ++c) {
166 CallbackAbstract& callback = *callbacks_[c];
167 callback(*this);
168 }
169
170 if (steplength_ > th_stepdec_ && dV_ >= 0.) {
171 decreaseRegularization();
172 }
173 if (steplength_ <= th_stepinc_ || std::abs(d_[1]) <= th_feas_) {
174 if (preg_ == reg_max_) {
175 STOP_PROFILER("SolverIntro::solve");
176 return false;
177 }
178 increaseRegularization();
179 }
180
181 if (is_feasible_ && stop_ < th_stop_) {
182 STOP_PROFILER("SolverIntro::solve");
183 return true;
184 }
185 }
186 STOP_PROFILER("SolverIntro::solve");
187 return false;
188}
189
190double SolverIntro::tryStep(const double steplength) {
191 forwardPass(steplength);
192 hfeas_try_ = computeEqualityFeasibility();
193 return cost_ - cost_try_;
194}
195
196double SolverIntro::stoppingCriteria() {
197 stop_ = std::max(hfeas_, std::abs(d_[0] + 0.5 * d_[1]));
198 return stop_;
199}
200
201void SolverIntro::resizeData() {
202 START_PROFILER("SolverIntro::resizeData");
203 SolverFDDP::resizeData();
204
205 const std::size_t T = problem_->get_T();
206 const std::size_t ndx = problem_->get_ndx();
207 const std::vector<std::shared_ptr<ActionModelAbstract> >& models =
208 problem_->get_runningModels();
209 for (std::size_t t = 0; t < T; ++t) {
210 const std::shared_ptr<ActionModelAbstract>& model = models[t];
211 const std::size_t nu = model->get_nu();
212 const std::size_t nh = model->get_nh();
213 KQuu_tmp_[t].conservativeResize(ndx, nu);
214 YZ_[t].conservativeResize(nu, nu);
215 Hy_[t].conservativeResize(nh, nh);
216 Qz_[t].conservativeResize(nh);
217 Qzz_[t].conservativeResize(nh, nh);
218 Qxz_[t].conservativeResize(ndx, nh);
219 Quz_[t].conservativeResize(nu, nh);
220 kz_[t].conservativeResize(nu);
221 Kz_[t].conservativeResize(nu, ndx);
222 ks_[t].conservativeResize(nh);
223 Ks_[t].conservativeResize(nh, ndx);
224 QuuinvHuT_[t].conservativeResize(nu, nh);
225 }
226 STOP_PROFILER("SolverIntro::resizeData");
227}
228
229double SolverIntro::calcDiff() {
230 START_PROFILER("SolverIntro::calcDiff");
231 SolverFDDP::calcDiff();
232 const std::size_t T = problem_->get_T();
233 const std::vector<std::shared_ptr<ActionModelAbstract> >& models =
234 problem_->get_runningModels();
235 const std::vector<std::shared_ptr<ActionDataAbstract> >& datas =
236 problem_->get_runningDatas();
237 switch (eq_solver_) {
238 case LuNull:
239#ifdef CROCODDYL_WITH_MULTITHREADING
240#pragma omp parallel for num_threads(problem_->get_nthreads())
241#endif
242 for (std::size_t t = 0; t < T; ++t) {
243 const std::shared_ptr<crocoddyl::ActionModelAbstract>& model =
244 models[t];
245 const std::shared_ptr<crocoddyl::ActionDataAbstract>& data = datas[t];
246 if (model->get_nu() > 0 && model->get_nh() > 0) {
247 Hu_lu_[t].compute(data->Hu);
248 YZ_[t] << Hu_lu_[t].matrixLU().transpose(), Hu_lu_[t].kernel();
249 Hu_rank_[t] = Hu_lu_[t].rank();
250 const Eigen::Block<Eigen::MatrixXd, Eigen::Dynamic, Eigen::Dynamic,
251 Eigen::RowMajor>
252 Y = YZ_[t].leftCols(Hu_lu_[t].rank());
253 Hy_[t].noalias() = data->Hu * Y;
254 Hy_lu_[t].compute(Hy_[t]);
255 const Eigen::Inverse<Eigen::PartialPivLU<Eigen::MatrixXd> > Hy_inv =
256 Hy_lu_[t].inverse();
257 ks_[t].noalias() = Hy_inv * data->h;
258 Ks_[t].noalias() = Hy_inv * data->Hx;
259 kz_[t].noalias() = Y * ks_[t];
260 Kz_[t].noalias() = Y * Ks_[t];
261 }
262 }
263 break;
264 case QrNull:
265#ifdef CROCODDYL_WITH_MULTITHREADING
266#pragma omp parallel for num_threads(problem_->get_nthreads())
267#endif
268 for (std::size_t t = 0; t < T; ++t) {
269 const std::shared_ptr<crocoddyl::ActionModelAbstract>& model =
270 models[t];
271 const std::shared_ptr<crocoddyl::ActionDataAbstract>& data = datas[t];
272 if (model->get_nu() > 0 && model->get_nh() > 0) {
273 Hu_qr_[t].compute(data->Hu.transpose());
274 YZ_[t] = Hu_qr_[t].householderQ();
275 Hu_rank_[t] = Hu_qr_[t].rank();
276 const Eigen::Block<Eigen::MatrixXd, Eigen::Dynamic, Eigen::Dynamic,
277 Eigen::RowMajor>
278 Y = YZ_[t].leftCols(Hu_qr_[t].rank());
279 Hy_[t].noalias() = data->Hu * Y;
280 Hy_lu_[t].compute(Hy_[t]);
281 const Eigen::Inverse<Eigen::PartialPivLU<Eigen::MatrixXd> > Hy_inv =
282 Hy_lu_[t].inverse();
283 ks_[t].noalias() = Hy_inv * data->h;
284 Ks_[t].noalias() = Hy_inv * data->Hx;
285 kz_[t].noalias() = Y * ks_[t];
286 Kz_[t].noalias() = Y * Ks_[t];
287 }
288 }
289 break;
290 case Schur:
291 break;
292 }
293
294 STOP_PROFILER("SolverIntro::calcDiff");
295 return cost_;
296}
297
298void SolverIntro::computeValueFunction(
299 const std::size_t t, const std::shared_ptr<ActionModelAbstract>& model) {
300 const std::size_t nu = model->get_nu();
301 Vx_[t] = Qx_[t];
302 Vxx_[t] = Qxx_[t];
303 if (nu != 0) {
304 START_PROFILER("SolverIntro::Vx");
305 Quuk_[t].noalias() = Quu_[t] * k_[t];
306 Vx_[t].noalias() -= Qxu_[t] * k_[t];
307 Qu_[t] -= Quuk_[t];
308 Vx_[t].noalias() -= K_[t].transpose() * Qu_[t];
309 Qu_[t] += Quuk_[t];
310 STOP_PROFILER("SolverIntro::Vx");
311 START_PROFILER("SolverIntro::Vxx");
312 KQuu_tmp_[t].noalias() = K_[t].transpose() * Quu_[t];
313 KQuu_tmp_[t].noalias() -= 2 * Qxu_[t];
314 Vxx_[t].noalias() += KQuu_tmp_[t] * K_[t];
315 STOP_PROFILER("SolverIntro::Vxx");
316 }
317 Vxx_tmp_ = 0.5 * (Vxx_[t] + Vxx_[t].transpose());
318 Vxx_[t] = Vxx_tmp_;
319
320 if (!std::isnan(preg_)) {
321 Vxx_[t].diagonal().array() += preg_;
322 }
323
324 // Compute and store the Vx gradient at end of the interval (rollout state)
325 if (!is_feasible_) {
326 Vx_[t].noalias() += Vxx_[t] * fs_[t];
327 }
328}
329
330void SolverIntro::computeGains(const std::size_t t) {
331 START_PROFILER("SolverIntro::computeGains");
332 const std::shared_ptr<crocoddyl::ActionModelAbstract>& model =
333 problem_->get_runningModels()[t];
334 const std::shared_ptr<crocoddyl::ActionDataAbstract>& data =
335 problem_->get_runningDatas()[t];
336
337 const std::size_t nu = model->get_nu();
338 const std::size_t nh = model->get_nh();
339 switch (eq_solver_) {
340 case LuNull:
341 case QrNull:
342 if (nu > 0 && nh > 0) {
343 START_PROFILER("SolverIntro::Qzz_inv");
344 const std::size_t rank = Hu_rank_[t];
345 const std::size_t nullity = data->Hu.cols() - rank;
346 const Eigen::Block<Eigen::MatrixXd, Eigen::Dynamic, Eigen::Dynamic,
347 Eigen::RowMajor>
348 Z = YZ_[t].rightCols(nullity);
349 Quz_[t].noalias() = Quu_[t] * Z;
350 Qzz_[t].noalias() = Z.transpose() * Quz_[t];
351 Qzz_llt_[t].compute(Qzz_[t]);
352 STOP_PROFILER("SolverIntro::Qzz_inv");
353 const Eigen::ComputationInfo& info = Qzz_llt_[t].info();
354 if (info != Eigen::Success) {
355 throw_pretty("backward error");
356 }
357
358 k_[t] = kz_[t];
359 K_[t] = Kz_[t];
360 Eigen::Transpose<Eigen::MatrixXd> QzzinvQzu = Quz_[t].transpose();
361 Qzz_llt_[t].solveInPlace(QzzinvQzu);
362 Qz_[t].noalias() = Z.transpose() * Qu_[t];
363 Qzz_llt_[t].solveInPlace(Qz_[t]);
364 Qxz_[t].noalias() = Qxu_[t] * Z;
365 Eigen::Transpose<Eigen::MatrixXd> Qzx = Qxz_[t].transpose();
366 Qzz_llt_[t].solveInPlace(Qzx);
367 Qz_[t].noalias() -= QzzinvQzu * kz_[t];
368 Qzx.noalias() -= QzzinvQzu * Kz_[t];
369 k_[t].noalias() += Z * Qz_[t];
370 K_[t].noalias() += Z * Qzx;
371 } else {
372 SolverFDDP::computeGains(t);
373 }
374 break;
375 case Schur:
376 SolverFDDP::computeGains(t);
377 if (nu > 0 && nh > 0) {
378 START_PROFILER("SolverIntro::Qzz_inv");
379 QuuinvHuT_[t] = data->Hu.transpose();
380 Quu_llt_[t].solveInPlace(QuuinvHuT_[t]);
381 Qzz_[t].noalias() = data->Hu * QuuinvHuT_[t];
382 Qzz_llt_[t].compute(Qzz_[t]);
383 STOP_PROFILER("SolverIntro::Qzz_inv");
384 const Eigen::ComputationInfo& info = Qzz_llt_[t].info();
385 if (info != Eigen::Success) {
386 throw_pretty("backward error");
387 }
388 Eigen::Transpose<Eigen::MatrixXd> HuQuuinv = QuuinvHuT_[t].transpose();
389 Qzz_llt_[t].solveInPlace(HuQuuinv);
390 ks_[t] = data->h;
391 ks_[t].noalias() -= data->Hu * k_[t];
392 Ks_[t] = data->Hx;
393 Ks_[t].noalias() -= data->Hu * K_[t];
394 k_[t].noalias() += QuuinvHuT_[t] * ks_[t];
395 K_[t] += QuuinvHuT_[t] * Ks_[t];
396 }
397 break;
398 }
399 STOP_PROFILER("SolverIntro::computeGains");
400}
401
402EqualitySolverType SolverIntro::get_equality_solver() const {
403 return eq_solver_;
404}
405
406double SolverIntro::get_th_feas() const { return th_feas_; }
407
408double SolverIntro::get_rho() const { return rho_; }
409
410double SolverIntro::get_upsilon() const { return upsilon_; }
411
413
414const std::vector<std::size_t>& SolverIntro::get_Hu_rank() const {
415 return Hu_rank_;
416}
417
418const std::vector<Eigen::MatrixXd>& SolverIntro::get_YZ() const { return YZ_; }
419
420const std::vector<Eigen::MatrixXd>& SolverIntro::get_Qzz() const {
421 return Qzz_;
422}
423
424const std::vector<Eigen::MatrixXd>& SolverIntro::get_Qxz() const {
425 return Qxz_;
426}
427
428const std::vector<Eigen::MatrixXd>& SolverIntro::get_Quz() const {
429 return Quz_;
430}
431
432const std::vector<Eigen::VectorXd>& SolverIntro::get_Qz() const { return Qz_; }
433
434const std::vector<Eigen::MatrixXd>& SolverIntro::get_Hy() const { return Hy_; }
435
436const std::vector<Eigen::VectorXd>& SolverIntro::get_kz() const { return kz_; }
437
438const std::vector<Eigen::MatrixXd>& SolverIntro::get_Kz() const { return Kz_; }
439
440const std::vector<Eigen::VectorXd>& SolverIntro::get_ks() const { return ks_; }
441
442const std::vector<Eigen::MatrixXd>& SolverIntro::get_Ks() const { return Ks_; }
443
444void SolverIntro::set_equality_solver(const EqualitySolverType type) {
445 eq_solver_ = type;
446}
447
448void SolverIntro::set_th_feas(const double th_feas) { th_feas_ = th_feas; }
449
450void SolverIntro::set_rho(const double rho) {
451 if (0. >= rho || rho > 1.) {
452 throw_pretty("Invalid argument: " << "rho value should between 0 and 1.");
453 }
454 rho_ = rho;
455}
456
457void SolverIntro::set_zero_upsilon(const bool zero_upsilon) {
458 zero_upsilon_ = zero_upsilon;
459}
460
461} // namespace crocoddyl
Feasibility-driven Differential Dynamic Programming (FDDP) solver.
Definition fddp.hpp:58
double th_acceptnegstep_
Definition fddp.hpp:112
virtual const Eigen::Vector2d & expectedImprovement()
Return the expected improvement from a given current search direction .
Definition fddp.cpp:124
void updateExpectedImprovement()
Update internal values for computing the expected improvement.
Definition fddp.cpp:151
std::vector< Eigen::MatrixXd > Kz_
Feedback gain in the nullspace of .
Definition intro.hpp:192
std::vector< Eigen::FullPivLU< Eigen::MatrixXd > > Hu_lu_
Definition intro.hpp:200
std::vector< Eigen::MatrixXd > Hy_
Definition intro.hpp:179
double th_feas_
Threshold for switching to feasibility.
Definition intro.hpp:162
std::vector< std::size_t > Hu_rank_
Rank of the control Jacobian of the equality constraints.
Definition intro.hpp:172
std::vector< Eigen::MatrixXd > Qxz_
Hessian of the reduced Hamiltonian .
Definition intro.hpp:186
std::vector< Eigen::VectorXd > Qz_
Jacobian of the reduced Hamiltonian .
Definition intro.hpp:182
double get_th_feas() const
Return the threshold for switching to feasibility.
Definition intro.cpp:406
const std::vector< Eigen::VectorXd > & get_kz() const
Return feedforward term related to the nullspace of .
Definition intro.cpp:436
EqualitySolverType get_equality_solver() const
Return the type of solver used for handling the equality constraints.
Definition intro.cpp:402
const std::vector< Eigen::MatrixXd > & get_YZ() const
Return the rank of control-equality constraints \mathbf{H_u}\f.
Definition intro.cpp:418
const std::vector< Eigen::MatrixXd > & get_Kz() const
Return feedback gain related to the nullspace of .
Definition intro.cpp:438
void set_equality_solver(const EqualitySolverType type)
Modify the type of solver used for handling the equality constraints.
Definition intro.cpp:444
std::vector< Eigen::MatrixXd > Quz_
Hessian of the reduced Hamiltonian .
Definition intro.hpp:188
std::vector< Eigen::MatrixXd > Ks_
Feedback gain related to the equality constraints.
Definition intro.hpp:196
std::vector< Eigen::LLT< Eigen::MatrixXd > > Qzz_llt_
Cholesky LLT solver.
Definition intro.hpp:198
std::vector< Eigen::ColPivHouseholderQR< Eigen::MatrixXd > > Hu_qr_
Definition intro.hpp:203
std::vector< Eigen::MatrixXd > Qzz_
Hessian of the reduced Hamiltonian .
Definition intro.hpp:184
void set_zero_upsilon(const bool zero_upsilon)
Modify the zero-upsilon label.
Definition intro.cpp:457
EIGEN_MAKE_ALIGNED_OPERATOR_NEW SolverIntro(std::shared_ptr< ShootingProblem > problem)
Initialize the INTRO solver.
Definition intro.cpp:18
const std::vector< Eigen::MatrixXd > & get_Hy() const
Return span-projected Jacobian of the equality-constraint with respect to the control.
Definition intro.cpp:434
double get_rho() const
Return the rho parameter used in the merit function.
Definition intro.cpp:408
const std::vector< Eigen::MatrixXd > & get_Qxz() const
Return Hessian of the reduced Hamiltonian .
Definition intro.cpp:424
const std::vector< Eigen::MatrixXd > & get_Ks() const
Return feedback gain related to the equality constraints.
Definition intro.cpp:442
void set_th_feas(const double th_feas)
Modify the threshold for switching to feasibility.
Definition intro.cpp:448
bool get_zero_upsilon() const
Return the zero-upsilon label.
Definition intro.cpp:412
double get_upsilon() const
Return the estimated penalty parameter that balances relative contribution of the cost function and e...
Definition intro.cpp:410
std::vector< Eigen::MatrixXd > YZ_
Definition intro.hpp:175
const std::vector< Eigen::MatrixXd > & get_Quz() const
Return Hessian of the reduced Hamiltonian .
Definition intro.cpp:428
enum EqualitySolverType eq_solver_
Strategy used for handling the equality constraints.
Definition intro.hpp:160
const std::vector< Eigen::MatrixXd > & get_Qzz() const
Return Hessian of the reduced Hamiltonian .
Definition intro.cpp:420
std::vector< Eigen::VectorXd > kz_
Feedforward term in the nullspace of .
Definition intro.hpp:190
const std::vector< Eigen::VectorXd > & get_ks() const
Return feedforward term related to the equality constraints.
Definition intro.cpp:440
const std::vector< Eigen::VectorXd > & get_Qz() const
Return Jacobian of the reduced Hamiltonian .
Definition intro.cpp:432
std::vector< Eigen::PartialPivLU< Eigen::MatrixXd > > Hy_lu_
Definition intro.hpp:206
std::vector< Eigen::VectorXd > ks_
Feedforward term related to the equality constraints.
Definition intro.hpp:194
void set_rho(const double rho)
Modify the rho parameter used in the merit function.
Definition intro.cpp:450