- 3.0.2 optimal control module.
NLOCBackendBase-impl.hpp
Go to the documentation of this file.
1 /**********************************************************************************************************************
2 This file is part of the Control Toolbox (https://github.com/ethz-adrl/control-toolbox), copyright by ETH Zurich.
3 Licensed under the BSD-2 license (see LICENSE file in main directory)
4 **********************************************************************************************************************/
5 
6 #pragma once
7 
8 namespace ct {
9 namespace optcon {
10 
11 
12 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
14  const OptConProblem_t& optConProblem,
15  const Settings_t& settings)
16  : NLOCBackendBase(createSystemInterface(optConProblem, settings), settings)
17 {
18 }
19 
20 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
22  const OptConProblem_t& optConProblem,
23  const std::string& settingsFile,
24  bool verbose,
25  const std::string& ns)
26  : NLOCBackendBase(optConProblem, Settings_t::fromConfigFile(settingsFile, verbose, ns))
27 {
28 }
29 
30 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
32  const systemInterfacePtr_t& systemInterface,
33  const Settings_t& settings)
34  : initialized_(false),
35  configured_(false),
36  iteration_(0),
37  firstRollout_(true),
38  settings_(settings),
39  K_(0),
42  d_norm_(0.0),
43  e_box_norm_(0.0),
44  e_gen_norm_(0.0),
45  lx_norm_(0.0),
46  lu_norm_(0.0),
47  intermediateCostBest_(std::numeric_limits<SCALAR>::infinity()),
48  finalCostBest_(std::numeric_limits<SCALAR>::infinity()),
49  lowestCost_(std::numeric_limits<SCALAR>::infinity()),
50  intermediateCostPrevious_(std::numeric_limits<SCALAR>::infinity()),
51  finalCostPrevious_(std::numeric_limits<SCALAR>::infinity()),
52  alphaBest_(-1),
53  lqocProblem_(new LQOCProblem<STATE_DIM, CONTROL_DIM, SCALAR>()),
54  systemInterface_(systemInterface),
55  inputBoxConstraints_(settings.nThreads + 1, nullptr), // initialize constraints with null
56  stateBoxConstraints_(settings.nThreads + 1, nullptr), // initialize constraints with null
57  generalConstraints_(settings.nThreads + 1, nullptr), // initialize constraints with null
58  lqpCounter_(0)
59 {
60  Eigen::initParallel();
61 
62  systemInterface_->initialize();
63 
64  configure(settings);
65 
66  changeTimeHorizon(systemInterface_->getOptConProblem().getTimeHorizon());
67  changeInitialState(systemInterface_->getOptConProblem().getInitialState());
68  changeCostFunction(systemInterface_->getOptConProblem().getCostFunction());
69 
70  // if the optimal problem has constraints, change
71  if (systemInterface_->getOptConProblem().getInputBoxConstraints())
72  {
73  changeInputBoxConstraints(systemInterface_->getOptConProblem().getInputBoxConstraints());
74  }
75  if (systemInterface_->getOptConProblem().getStateBoxConstraints())
76  {
77  changeStateBoxConstraints(systemInterface_->getOptConProblem().getStateBoxConstraints());
78  }
79 
80  if (systemInterface_->getOptConProblem().getGeneralConstraints())
81  {
82  changeGeneralConstraints(systemInterface_->getOptConProblem().getGeneralConstraints());
83  }
84 }
85 
86 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
88  const systemInterfacePtr_t& systemInterface,
89  const std::string& settingsFile,
90  bool verbose,
91  const std::string& ns)
92  : NLOCBackendBase(systemInterface, Settings_t::fromConfigFile(settingsFile, verbose, ns))
93 {
94 }
95 
96 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
98 {
99 }
100 
101 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
102 template <typename T>
103 typename std::enable_if<std::is_same<T, ContinuousOptConProblem<STATE_DIM, CONTROL_DIM, SCALAR>>::value,
106  const OptConProblem_t& optConProblem,
107  const Settings_t& settings)
108 {
109  return systemInterfacePtr_t(
111 }
112 
113 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
114 template <typename T>
115 typename std::enable_if<std::is_same<T, DiscreteOptConProblem<STATE_DIM, CONTROL_DIM, SCALAR>>::value,
118  const OptConProblem_t& optConProblem,
119  const Settings_t& settings)
120 {
121  return systemInterfacePtr_t(
123 }
124 
125 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
127  const Policy_t& initialGuess)
128 {
129  if (initialGuess.x_ref().size() < (size_t)K_ + 1)
130  {
131  std::cout << "Initial state guess length too short. Received length " << initialGuess.x_ref().size()
132  << ", expected " << K_ + 1 << std::endl;
133  throw(std::runtime_error("initial state guess to short"));
134  }
135 
136  if (initialGuess.uff().size() < (size_t)K_)
137  {
138  std::cout << "Initial control guess length too short. Received length " << initialGuess.uff().size()
139  << ", expected " << K_ << std::endl;
140  throw std::runtime_error("initial control guess to short");
141  }
142 
143  if (initialGuess.K().size() < (size_t)K_)
144  {
145  std::cout << "Initial feedback length too short. Received length " << initialGuess.K().size() << ", expected "
146  << K_ << std::endl;
147  throw std::runtime_error("initial control guess to short");
148  }
149 
150  u_ff_ = initialGuess.uff();
151  L_ = initialGuess.K();
152  x_ = initialGuess.x_ref();
153  x_prev_ = x_;
154  x_ref_lqr_ = x_;
155 
156  if (x_.size() > (size_t)K_ + 1)
157  {
158  std::cout << "Warning, initial state guess too long. Received length " << x_.size() << ", expected " << K_ + 1
159  << ", will truncate" << std::endl;
160  x_.resize(K_ + 1);
161  }
162 
163  if (u_ff_.size() > (size_t)K_)
164  {
165  std::cout << "Warning, initial control guess too long. Received length " << u_ff_.size() << ", expected " << K_
166  << ", will truncate" << std::endl;
167  u_ff_.resize(K_);
168  }
169 
170  if (L_.size() > (size_t)K_)
171  {
172  std::cout << "Warning, initial feedback guess too long. Received length " << L_.size() << ", expected " << K_
173  << ", will truncate" << std::endl;
174  L_.resize(K_);
175  }
176 
177  initialized_ = true;
178 
179  t_ = TimeArray(settings_.dt, x_.size(), 0.0);
180 
181  reset();
182 
183  // compute costs of the initial guess trajectory
187 }
188 
189 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
191 {
192  if (numStages == K_)
193  return;
194 
195  if (numStages < 1)
196  throw std::runtime_error("negative or zero time steps specified");
197 
198  K_ = numStages;
199 
200  t_ = TimeArray(settings_.dt, K_ + 1, 0.0);
201 
202  x_.resize(K_ + 1);
203  x_prev_.resize(K_ + 1);
204  xShot_.resize(K_ + 1);
205  delta_x_.resize(K_ + 1);
206  x_ref_lqr_.resize(K_ + 1);
207  delta_x_ref_lqr_.resize(K_ + 1);
208 
209  u_ff_.resize(K_);
210  u_ff_prev_.resize(K_);
211  delta_u_ff_.resize(K_);
212  d_.resize(K_ + 1);
213  L_.resize(K_);
214 
215  substepsX_->resize(K_ + 1);
216  substepsU_->resize(K_ + 1);
217 
218  resetDefects();
219 
220  systemInterface_->changeNumStages(K_);
221 
222  lqocProblem_->changeNumStages(K_);
223  lqocProblem_->setZero();
224 
225  lqocSolver_->setProblem(lqocProblem_);
226 }
227 
228 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
230 {
231  if (tf < 0)
232  throw std::runtime_error("negative time horizon specified");
233 
235 }
236 
237 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
240 {
241  if (x_.size() == 0)
242  x_.resize(1);
243 
244  x_[0] = x0;
245  reset(); // since initial state changed, we have to start fresh, i.e. with a rollout
246 }
247 
248 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
250  const typename OptConProblem_t::CostFunctionPtr_t& cf)
251 {
252  if (cf == nullptr)
253  throw std::runtime_error("cost function is nullptr");
254 
255  costFunctions_.resize(settings_.nThreads + 1);
256 
257  for (int i = 0; i < settings_.nThreads + 1; i++)
258  {
259  // make a deep copy
260  costFunctions_[i] = typename OptConProblem_t::CostFunctionPtr_t(cf->clone());
261  }
262 
263  // recompute cost if line search is active
264  // TODO: this should be multi-threaded to save time
265  if (iteration_ > 0 && (settings_.lineSearchSettings.type != LineSearchSettings::TYPE::NONE))
267 }
268 
269 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
271  const typename OptConProblem_t::DynamicsPtr_t& dyn)
272 {
273  systemInterface_->changeNonlinearSystem(dyn);
274 }
275 
276 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
278  const typename OptConProblem_t::ConstraintPtr_t& con)
279 {
280  if (con == nullptr)
281  throw std::runtime_error("NLOCBackendBase: box constraint is nullptr");
282 
284 
285  for (int i = 0; i < settings_.nThreads + 1; i++)
286  {
287  // make a deep copy
288  inputBoxConstraints_[i] = typename OptConProblem_t::ConstraintPtr_t(con->clone());
289  }
290 
291  // TODO can we do this multi-threaded?
292  if (iteration_ > 0 && (settings_.lineSearchSettings.type != LineSearchSettings::TYPE::NONE))
294 
296 }
297 
298 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
300  const typename OptConProblem_t::ConstraintPtr_t& con)
301 {
302  if (con == nullptr)
303  throw std::runtime_error("NLOCBackendBase: box constraint is nullptr");
304 
306 
307  for (int i = 0; i < settings_.nThreads + 1; i++)
308  {
309  // make a deep copy
310  stateBoxConstraints_[i] = typename OptConProblem_t::ConstraintPtr_t(con->clone());
311  }
312 
313  // TODO can we do this multi-threaded?
314  if (iteration_ > 0 && (settings_.lineSearchSettings.type != LineSearchSettings::TYPE::NONE))
316 
318 }
319 
320 
321 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
323  const typename OptConProblem_t::ConstraintPtr_t& con)
324 {
325  if (con == nullptr)
326  throw std::runtime_error("NLOCBackendBase: general constraint is nullptr");
327 
329 
330  for (int i = 0; i < settings_.nThreads + 1; i++)
331  {
332  // make a deep copy
333  generalConstraints_[i] = typename OptConProblem_t::ConstraintPtr_t(con->clone());
334  }
335 
336  // intermediate stages
337  for (int i = 0; i < K_; i++)
338  {
339  generalConstraints_[settings_.nThreads]->setCurrentStateAndControl(x_[i], u_ff_[i], i * settings_.dt);
340 
341  lqocProblem_->ng_[i] = generalConstraints_[settings_.nThreads]->getIntermediateConstraintsCount();
342 
343  lqocProblem_->C_[i].resize(lqocProblem_->ng_[i], STATE_DIM);
344  lqocProblem_->D_[i].resize(lqocProblem_->ng_[i], CONTROL_DIM);
345  lqocProblem_->d_lb_[i].resize(lqocProblem_->ng_[i], 1);
346  lqocProblem_->d_ub_[i].resize(lqocProblem_->ng_[i], 1);
347  }
348 
349  // terminal stage
350  lqocProblem_->ng_[K_] = generalConstraints_[settings_.nThreads]->getTerminalConstraintsCount();
351  lqocProblem_->C_[K_].resize(lqocProblem_->ng_[K_], STATE_DIM);
352  lqocProblem_->D_[K_].resize(lqocProblem_->ng_[K_], CONTROL_DIM);
353  lqocProblem_->d_lb_[K_].resize(lqocProblem_->ng_[K_], 1);
354  lqocProblem_->d_ub_[K_].resize(lqocProblem_->ng_[K_], 1);
355 
356  lqocSolver_->setProblem(lqocProblem_);
357 
358  // TODO can we do this multi-threaded?
359  if (iteration_ > 0 && (settings_.lineSearchSettings.type != LineSearchSettings::TYPE::NONE))
361 }
362 
363 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
365  const typename OptConProblem_t::LinearPtr_t& lin)
366 {
367  systemInterface_->changeLinearSystem(lin);
368 }
369 
370 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
372 {
373  if (K_ == 0)
374  throw std::runtime_error("Time horizon too small resulting in 0 steps");
375 
376  if (u_ff_.size() < (size_t)K_)
377  {
378  std::cout << "Provided initial feed forward controller too short, should be at least " << K_ << " but is "
379  << u_ff_.size() << " long." << std::endl;
380  throw(std::runtime_error("Provided initial feed forward controller too short"));
381  }
382 }
383 
384 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
386 {
387  if (!settings.parametersOk())
388  {
389  throw(std::runtime_error("Settings are incorrect. Aborting."));
390  }
391 
392  if (settings.nThreads != settings_.nThreads)
393  {
394  throw(std::runtime_error("Number of threads cannot be changed after instance has been created."));
395  }
396 
397  systemInterface_->configure(settings);
398 
399  // select the linear quadratic solver based on settings file
400  if (settings.lqocp_solver == NLOptConSettings::LQOCP_SOLVER::GNRICCATI_SOLVER)
401  {
402  lqocSolver_ = std::shared_ptr<GNRiccatiSolver<STATE_DIM, CONTROL_DIM, SCALAR>>(
404  }
405  else if (settings.lqocp_solver == NLOptConSettings::LQOCP_SOLVER::HPIPM_SOLVER)
406  {
407 #ifdef HPIPM
408  lqocSolver_ =
409  std::shared_ptr<HPIPMInterface<STATE_DIM, CONTROL_DIM>>(new HPIPMInterface<STATE_DIM, CONTROL_DIM>());
410 #else
411  throw std::runtime_error("HPIPM selected but not built.");
412 #endif
413  }
414  else
415  throw std::runtime_error("Solver for Linear Quadratic Optimal Control Problem wrongly specified.");
416 
417  // set number of Eigen Threads (requires -fopenmp)
418  if (settings_.nThreadsEigen > 1)
419  {
420  Eigen::setNbThreads(settings.nThreadsEigen);
421 #ifdef DEBUG_PRINT_MP
422  std::cout << "[MP] Eigen using " << Eigen::nbThreads() << " threads." << std::endl;
423 #endif
424  }
425 
426  lqocSolver_->configure(settings);
427 
428  settings_ = settings;
429 
430  reset();
431 
432  configured_ = true;
433 }
434 
435 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
437  const size_t k,
438  ControlVectorArray& u_local,
439  StateVectorArray& x_local,
440  const StateVectorArray& x_ref_lqr_local,
441  StateVectorArray& xShot,
442  StateSubsteps& substepsX,
443  ControlSubsteps& substepsU,
444  std::atomic_bool* terminationFlag) const
445 {
446  const int K_local = K_;
447 
448  if (u_local.size() < (size_t)K_)
449  throw std::runtime_error("rolloutSingleShot: u_local is too short.");
450  if (x_local.size() < (size_t)K_ + 1)
451  throw std::runtime_error("rolloutSingleShot: x_local is too short.");
452  if (xShot.size() < (size_t)K_ + 1)
453  throw std::runtime_error("rolloutSingleShot: xShot is too short.");
454 
455  xShot[k] = x_local[k]; // initialize
456 
458  int K_stop = k + getNumStepsPerShot();
459  if (K_stop > K_local)
460  K_stop = K_local;
461 
462  // for each control step
463  for (int i = (int)k; i < K_stop; i++)
464  {
465  if (terminationFlag && *terminationFlag)
466  return false;
467 
468  if (i > (int)k)
469  {
470  xShot[i] = xShot[i - 1];
471  }
472 
473  if (settings_.closedLoopShooting()) // overwrite control
474  u_local[i] += L_[i] * (xShot[i] - x_ref_lqr_local[i]);
475 
477  if (i > (int)k)
478  {
479  x_local[i] = xShot[i - 1];
480  }
481 
482  state_vector_t stateNext;
483  systemInterface_->propagateControlledDynamics(xShot[i], i, u_local[i], stateNext, threadId);
484  xShot[i] = stateNext;
485 
486  if (i == K_local - 1)
487  x_local[K_local] = xShot[K_local - 1];
488 
489 
490  // check if nan
491  for (size_t j = 0; j < STATE_DIM; j++)
492  {
493  if (std::isnan(x_local[i](j)))
494  {
495  x_local.resize(K_local + 1,
496  ct::core::StateVector<STATE_DIM, SCALAR>::Constant(std::numeric_limits<SCALAR>::quiet_NaN()));
497  u_local.resize(K_local,
498  ct::core::ControlVector<CONTROL_DIM, SCALAR>::Constant(std::numeric_limits<SCALAR>::quiet_NaN()));
499  return false;
500  }
501  }
502  for (size_t j = 0; j < CONTROL_DIM; j++)
503  {
504  if (std::isnan(u_local[i](j)))
505  {
506  x_local.resize(K_local + 1,
507  ct::core::StateVector<STATE_DIM, SCALAR>::Constant(std::numeric_limits<SCALAR>::quiet_NaN()));
508  u_local.resize(K_local,
509  ct::core::ControlVector<CONTROL_DIM, SCALAR>::Constant(std::numeric_limits<SCALAR>::quiet_NaN()));
510  std::cout << "control unstable" << std::endl;
511  return false;
512  }
513  }
514 
515  // get substeps for later sensitvity calculation
516  systemInterface_->getSubstates(substepsX[i], threadId);
517  systemInterface_->getSubcontrols(substepsU[i], threadId);
518  }
519 
520  return true;
521 }
522 
523 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
525  size_t threadId,
526  size_t firstIndex,
527  size_t lastIndex,
528  ControlVectorArray& u_ff_local,
529  StateVectorArray& x_local,
530  const StateVectorArray& x_ref_lqr,
531  StateVectorArray& xShot,
532  StateVectorArray& d,
533  StateSubsteps& substepsX,
534  ControlSubsteps& substepsU,
535  std::atomic_bool* terminationFlag) const
536 {
538  d.setConstant(state_vector_t::Zero());
539 
540  for (size_t k = firstIndex; k <= lastIndex; k = k + getNumStepsPerShot())
541  {
542  // first rollout the shot
543  bool dynamicsGood = rolloutSingleShot(
544  threadId, k, u_ff_local, x_local, x_ref_lqr, xShot, substepsX, substepsU, terminationFlag);
545 
546  if (!dynamicsGood)
547  return false;
548 
549  // then compute the corresponding defect
550  computeSingleDefect(k, x_local, xShot, d);
551  }
552  return true;
553 }
554 
555 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
557  const StateVectorArray& x_local,
558  const StateVectorArray& xShot,
559  StateVectorArray& d) const
560 {
562  int k_next = std::min(K_, (int)k + settings_.K_shot);
563 
564  if (k_next < K_)
565  {
566  d[k_next - 1] = xShot[k_next - 1] - x_local[k_next];
567  }
569 }
570 
571 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
573  size_t threadId,
576  scalar_t& intermediateCost,
577  scalar_t& finalCost) const
578 {
579  intermediateCost = 0;
580 
581  for (size_t k = 0; k < (size_t)K_; k++)
582  {
583  // feed current state and control to cost function
584  costFunctions_[threadId]->setCurrentStateAndControl(x_local[k], u_local[k], settings_.dt * k);
585 
586  // derivative of cost with respect to state
587  intermediateCost += costFunctions_[threadId]->evaluateIntermediate();
588  }
589  intermediateCost *= settings_.dt;
590 
591  costFunctions_[threadId]->setCurrentStateAndControl(x_local[K_], control_vector_t::Zero(), settings_.dt * K_);
592  finalCost = costFunctions_[threadId]->evaluateTerminal();
593 }
594 
595 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
597  size_t threadId,
600  scalar_t& e_tot) const
601 {
602  e_tot = 0;
603 
604  // intermediate constraints
605  for (size_t k = 0; k < (size_t)K_; k++)
606  {
607  if (inputBoxConstraints_[threadId] != nullptr)
608  {
609  if (inputBoxConstraints_[threadId]->getIntermediateConstraintsCount() > 0)
610  {
611  inputBoxConstraints_[threadId]->setCurrentStateAndControl(x_local[k], u_local[k], settings_.dt * k);
612  Eigen::Matrix<SCALAR, -1, 1> box_err =
613  inputBoxConstraints_[threadId]->getTotalBoundsViolationIntermediate();
614  e_tot += box_err.template lpNorm<1>();
615  }
616  }
617  if (stateBoxConstraints_[threadId] != nullptr)
618  {
619  if (stateBoxConstraints_[threadId]->getIntermediateConstraintsCount() > 0)
620  {
621  stateBoxConstraints_[threadId]->setCurrentStateAndControl(x_local[k], u_local[k], settings_.dt * k);
622  Eigen::Matrix<SCALAR, -1, 1> box_err =
623  stateBoxConstraints_[threadId]->getTotalBoundsViolationIntermediate();
624  e_tot += box_err.template lpNorm<1>();
625  }
626  }
627  }
628 
629  // normalize integrated violation by time
630  e_tot *= settings_.dt;
631 
632  // terminal constraint violation
633  if (stateBoxConstraints_[threadId] != nullptr)
634  {
635  if (stateBoxConstraints_[threadId]->getTerminalConstraintsCount() > 0)
636  {
637  stateBoxConstraints_[threadId]->setCurrentStateAndControl(
638  x_local[K_], control_vector_t::Zero(), settings_.dt * K_);
639  Eigen::Matrix<SCALAR, -1, 1> box_err = stateBoxConstraints_[threadId]->getTotalBoundsViolationTerminal();
640  e_tot += box_err.template lpNorm<1>();
641  }
642  }
643 }
644 
645 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
650  scalar_t& e_tot) const
651 {
652  e_tot = 0;
653 
654  // intermediate constraints
655  for (size_t k = 0; k < (size_t)K_; k++)
656  {
657  if (generalConstraints_[threadId] != nullptr)
658  {
659  if (generalConstraints_[threadId]->getIntermediateConstraintsCount() > 0)
660  {
661  generalConstraints_[threadId]->setCurrentStateAndControl(x_local[k], u_local[k], settings_.dt * k);
662  Eigen::Matrix<SCALAR, -1, 1> gen_err =
663  generalConstraints_[threadId]->getTotalBoundsViolationIntermediate();
664  e_tot += gen_err.template lpNorm<1>();
665  }
666  }
667  }
668 
669  // normalize integrated violation by time
670  e_tot *= settings_.dt;
671 
672  if (generalConstraints_[threadId] != nullptr)
673  {
674  if (generalConstraints_[threadId]->getTerminalConstraintsCount() > 0)
675  {
676  generalConstraints_[threadId]->setCurrentStateAndControl(
677  x_local[K_], control_vector_t::Zero(), settings_.dt * K_);
678  Eigen::Matrix<SCALAR, -1, 1> gen_err = generalConstraints_[threadId]->getTotalBoundsViolationTerminal();
679  e_tot += gen_err.template lpNorm<1>();
680  }
681  }
682 }
683 
684 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
686  size_t k)
687 {
689  const scalar_t& dt = settings_.dt;
690 
691  assert(lqocProblem_ != nullptr);
692 
693  assert(lqocProblem_->A_.size() > k);
694  assert(lqocProblem_->B_.size() > k);
695  assert(lqocProblem_->b_.size() > k);
696 
697 
699  // compute A_n and B_n
700  systemInterface_->setSubstepTrajectoryReference(substepsX_, substepsU_, threadId);
701  systemInterface_->getAandB(x_[k], u_ff_[k], xShot_[k], (int)k, settings_.K_sim, p.A_[k], p.B_[k], threadId);
702 
703  // compute dynamics offset term b_n
704  p.b_[k] = d_[k];
705 
706  // feed current state and control to cost function
707  costFunctions_[threadId]->setCurrentStateAndControl(x_[k], u_ff_[k], dt * k);
708 
709  // By using the following order of evaluations, we avoid caching matrices
710  // second derivative w.r.t state
711  p.Q_[k] = costFunctions_[threadId]->stateSecondDerivativeIntermediate() * dt;
712  // second derivative w.r.t control
713  p.R_[k] = costFunctions_[threadId]->controlSecondDerivativeIntermediate() * dt;
714  // cross terms
715  p.P_[k] = costFunctions_[threadId]->stateControlDerivativeIntermediate() * dt;
716 
717  // derivative of cost with respect to state
718  p.qv_[k] = costFunctions_[threadId]->stateDerivativeIntermediate() * dt;
719  // derivative of cost with respect to control
720  p.rv_[k] = costFunctions_[threadId]->controlDerivativeIntermediate() * dt;
721 
722  // p.q_[k] = ... // not evaluated since we don't need it in GNMS/iLQR -- WARNING, potentially implement when using a different QP solver
723 }
724 
725 
726 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
728 {
729  // set box constraints if there are any
730  if (inputBoxConstraints_[settings_.nThreads] != nullptr)
731  {
732  // check number of intermediate box constraints
733  const int nb_u_intermediate =
734  inputBoxConstraints_[settings_.nThreads]->getJacobianInputNonZeroCountIntermediate();
735 
736  if (nb_u_intermediate > 0)
737  {
738  Eigen::VectorXi u_sparsity_row, u_sparsity_col_intermediate;
739 
740  inputBoxConstraints_[settings_.nThreads]->sparsityPatternInputIntermediate(
741  u_sparsity_row, u_sparsity_col_intermediate);
742 
743  lqocProblem_->setInputBoxConstraints(nb_u_intermediate,
744  inputBoxConstraints_[settings_.nThreads]->getLowerBoundsIntermediate(),
745  inputBoxConstraints_[settings_.nThreads]->getUpperBoundsIntermediate(), u_sparsity_col_intermediate,
746  u_ff_);
747  }
748  }
749 }
750 
751 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
753 {
754  if (stateBoxConstraints_[settings_.nThreads] != nullptr)
755  {
756  const int nb_x_intermediate =
757  stateBoxConstraints_[settings_.nThreads]->getJacobianStateNonZeroCountIntermediate();
758 
759  if (nb_x_intermediate > 0)
760  {
761  Eigen::VectorXi x_sparsity_row, x_sparsity_col_intermediate;
762 
763  stateBoxConstraints_[settings_.nThreads]->sparsityPatternStateIntermediate(
764  x_sparsity_row, x_sparsity_col_intermediate);
765 
766  lqocProblem_->setIntermediateStateBoxConstraints(nb_x_intermediate,
767  stateBoxConstraints_[settings_.nThreads]->getLowerBoundsIntermediate(),
768  stateBoxConstraints_[settings_.nThreads]->getUpperBoundsIntermediate(), x_sparsity_col_intermediate,
769  x_);
770  }
771 
772  // check number of terminal box constraints
773  const int nb_x_terminal = stateBoxConstraints_[settings_.nThreads]->getJacobianStateNonZeroCountTerminal();
774 
775  if (nb_x_terminal > 0)
776  {
777  Eigen::VectorXi x_sparsity_row_terminal, x_sparsity_col_terminal;
778 
779  stateBoxConstraints_[settings_.nThreads]->sparsityPatternStateTerminal(
780  x_sparsity_row_terminal, x_sparsity_col_terminal);
781 
782  lqocProblem_->setTerminalBoxConstraints(nb_x_terminal,
783  stateBoxConstraints_[settings_.nThreads]->getLowerBoundsTerminal(),
784  stateBoxConstraints_[settings_.nThreads]->getUpperBoundsTerminal(), x_sparsity_col_terminal, x_.back());
785  }
786  }
787 }
788 
789 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
791  size_t threadId,
792  size_t k)
793 {
794  // set general if there are any
795  if (generalConstraints_[threadId] != nullptr)
796  {
798  const scalar_t& dt = settings_.dt;
799 
800  // treat general constraints
801  generalConstraints_[threadId]->setCurrentStateAndControl(x_[k], u_ff_[k], dt * k);
802 
803  p.ng_[k] = generalConstraints_[threadId]->getIntermediateConstraintsCount();
804  if (p.ng_[k] > 0)
805  {
806  p.C_[k] = generalConstraints_[threadId]->jacobianStateIntermediate();
807  p.D_[k] = generalConstraints_[threadId]->jacobianInputIntermediate();
808 
809  Eigen::Matrix<SCALAR, Eigen::Dynamic, 1> g_eval = generalConstraints_[threadId]->evaluateIntermediate();
810 
811  // rewrite constraint boundaries in relative coordinates as required by LQOC problem
812  p.d_lb_[k] = generalConstraints_[threadId]->getLowerBoundsIntermediate() - g_eval;
813  p.d_ub_[k] = generalConstraints_[threadId]->getUpperBoundsIntermediate() - g_eval;
814  }
815  }
816 }
817 
818 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
820 {
822 
823  // feed current state and control to cost function
824  costFunctions_[settings_.nThreads]->setCurrentStateAndControl(x_[K_], control_vector_t::Zero(), settings_.dt * K_);
825 
826  // derivative of terminal cost with respect to state
827  p.Q_[K_] = costFunctions_[settings_.nThreads]->stateSecondDerivativeTerminal();
828  p.qv_[K_] = costFunctions_[settings_.nThreads]->stateDerivativeTerminal();
829  // p.q_[K_] = ... // omitted since not needed in GNMS/ILQR -- WARNING, potentially implement when using a different QP solver
830 
831  // init terminal general constraints, if any
832  if (generalConstraints_[settings_.nThreads] != nullptr)
833  {
834  p.ng_[K_] = generalConstraints_[settings_.nThreads]->getTerminalConstraintsCount();
835  if (p.ng_[K_] > 0)
836  {
837  p.C_[K_] = generalConstraints_[settings_.nThreads]->jacobianStateTerminal();
838  p.D_[K_] = generalConstraints_[settings_.nThreads]->jacobianInputTerminal();
839 
840  Eigen::Matrix<SCALAR, Eigen::Dynamic, 1> g_eval =
841  generalConstraints_[settings_.nThreads]->evaluateTerminal();
842 
843  p.d_lb_[K_] = generalConstraints_[settings_.nThreads]->getLowerBoundsTerminal() - g_eval;
844  p.d_ub_[K_] = generalConstraints_[settings_.nThreads]->getUpperBoundsTerminal() - g_eval;
845  }
846  }
847 }
848 
849 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
851 {
852  SCALAR d_norm_l1 = computeDefectsNorm<1>(d_);
853  SCALAR d_norm_l2 = computeDefectsNorm<2>(d_);
855 
858 
859  SCALAR totalMerit = intermediateCostBest_ + finalCostBest_ + settings_.meritFunctionRho * d_norm_l1 +
861 
862  SCALAR smallestEigenvalue = 0.0;
863  if (settings_.recordSmallestEigenvalue && settings_.lqocp_solver == Settings_t::LQOCP_SOLVER::GNRICCATI_SOLVER)
864  {
865  smallestEigenvalue = lqocSolver_->getSmallestEigenvalue();
866  }
867 
868 
869  summaryAllIterations_.iterations.push_back(iteration_);
870  summaryAllIterations_.defect_l1_norms.push_back(d_norm_l1);
871  summaryAllIterations_.defect_l2_norms.push_back(d_norm_l2);
872  summaryAllIterations_.e_box_norms.push_back(e_box_norm_);
873  summaryAllIterations_.e_gen_norms.push_back(e_gen_norm_);
874  summaryAllIterations_.lx_norms.push_back(lx_norm_);
875  summaryAllIterations_.lu_norms.push_back(lu_norm_);
876  summaryAllIterations_.intermediateCosts.push_back(intermediateCostBest_);
877  summaryAllIterations_.finalCosts.push_back(finalCostBest_);
878  summaryAllIterations_.totalCosts.push_back(totalCost);
879  summaryAllIterations_.merits.push_back(totalMerit);
880  summaryAllIterations_.stepSizes.push_back(alphaBest_);
881  summaryAllIterations_.smallestEigenvalues.push_back(smallestEigenvalue);
882 
884  summaryAllIterations_.printSummaryLastIteration();
885 
888  settings_.lqocp_solver == Settings_t::LQOCP_SOLVER::GNRICCATI_SOLVER)
889  {
890  std::cout << std::setprecision(15) << "smallest eigenvalue this iteration: " << smallestEigenvalue << std::endl;
891  }
892 }
893 
894 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
896 {
897 #ifdef MATLAB_FULL_LOG
898 
900  {
901  std::cout << "Logging to Matlab" << std::endl;
902 
904 
905  matFile_.open(settings_.loggingPrefix + "Log" + std::to_string(iteration) + ".mat");
906 
907  matFile_.put("iteration", iteration);
908  matFile_.put("K", K_);
909  matFile_.put("dt", settings_.dt);
910  matFile_.put("K_sim", settings_.K_sim);
911  matFile_.put("x", x_.toImplementation());
912  matFile_.put("u_ff", u_ff_.toImplementation());
913  matFile_.put("t", t_.toEigenTrajectory());
914  matFile_.put("d", d_.toImplementation());
915  matFile_.put("xShot", xShot_.toImplementation());
916 
917  matFile_.put("A", p.A_.toImplementation());
918  matFile_.put("B", p.B_.toImplementation());
919  matFile_.put("qv", p.qv_.toImplementation());
920  matFile_.put("Q", p.Q_.toImplementation());
921  matFile_.put("P", p.P_.toImplementation());
922  matFile_.put("rv", p.rv_.toImplementation());
923  matFile_.put("R", p.R_.toImplementation());
924  matFile_.put("q", p.q_.toEigenTrajectory());
925 
926  matFile_.put("lx_norm", lx_norm_);
927  matFile_.put("lu_norm", lu_norm_);
928  matFile_.put("cost", getCost());
929  matFile_.put("alphaStep", alphaBest_);
930 
931  d_norm_ = computeDefectsNorm<1>(d_);
932  matFile_.put("d_norm", d_norm_);
933 
936  matFile_.put("e_box_norm", e_box_norm_);
937  matFile_.put("e_gen_norm", e_gen_norm_);
938 
939  matFile_.close();
940  }
941 #endif //MATLAB_FULL_LOG
942 }
943 
944 
945 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
947 {
948 #ifdef MATLAB
950  {
951  std::cout << "Logging init guess to Matlab" << std::endl;
952 
953  matFile_.open(settings_.loggingPrefix + "LogInit.mat");
954 
955  matFile_.put("K", K_);
956  matFile_.put("dt", settings_.dt);
957  matFile_.put("K_sim", settings_.K_sim);
958 
959  matFile_.put("x", x_.toImplementation());
960  matFile_.put("u_ff", u_ff_.toImplementation());
961  matFile_.put("d", d_);
962  matFile_.put("cost", getCost());
963 
964  d_norm_ = computeDefectsNorm<1>(d_);
965  matFile_.put("d_norm", d_norm_);
966 
969  matFile_.put("e_box_norm", e_box_norm_);
970  matFile_.put("e_gen_norm", e_gen_norm_);
971 
972  matFile_.close();
973  }
974 #endif
975 }
976 
977 
978 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
981 {
983 
984  core::tpl::TimeArray<SCALAR> t_control = t_;
985  t_control.pop_back();
986 
988 }
989 
990 
991 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
994 {
996 
997  core::tpl::TimeArray<SCALAR> t_control = t_;
998 
999  return core::StateTrajectory<STATE_DIM, SCALAR>(t_control, x_);
1000 }
1001 
1002 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1004 {
1006 }
1007 
1008 
1009 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1011 {
1012  // lowest cost
1013  scalar_t lowestCostPrevious;
1014 
1015  // backup controller that led to current trajectory
1016  u_ff_prev_ = u_ff_;
1017  x_prev_ = x_;
1018 
1019 
1020  if (settings_.lineSearchSettings.type == LineSearchSettings::TYPE::NONE) // do full step updates
1021  {
1022  // lowest cost is cost of last rollout
1023  lowestCostPrevious = intermediateCostBest_ + finalCostBest_;
1024 
1025  // update controls and states
1026  doFullStepUpdate();
1027 
1028  resetDefects();
1029 
1030  rolloutShots(0, K_ - 1);
1031  d_norm_ = computeDefectsNorm<1>(d_);
1032 
1033  updateCosts();
1034 
1036 
1037  // compute the control and state update norms separately here, since they are usually different from the pure lqoc solver update
1038  lu_norm_ = computeDiscreteArrayNorm<ControlVectorArray, 2>(u_ff_prev_, u_ff_);
1039  lx_norm_ = computeDiscreteArrayNorm<StateVectorArray, 2>(x_prev_, x_);
1040 
1041  x_prev_ = x_;
1042  alphaBest_ = 1;
1043  }
1044  else // do line search over a merit function trading off costs and constraint violations
1045  {
1046  // merit of previous trajectory
1047  d_norm_ = computeDefectsNorm<1>(d_);
1050  lowestCostPrevious = lowestCost_;
1051 
1052  resetDefects();
1053 
1054 
1056  {
1057  std::cout << "[LineSearch]: Starting line search." << std::endl;
1058  std::cout << "[LineSearch]: Cost of last rollout:\t" << intermediateCostBest_ + finalCostBest_ << std::endl;
1059  std::cout << "[LineSearch]: Defect norm last rollout:\t" << d_norm_ << std::endl;
1060  std::cout << "[LineSearch]: err box constr last rollout:\t" << e_box_norm_ << std::endl;
1061  std::cout << "[LineSearch]: err gen constr last rollout:\t" << e_gen_norm_ << std::endl;
1062  std::cout << "[LineSearch]: Merit of last rollout:\t" << lowestCost_ << std::endl;
1063  }
1064 
1066 
1068  {
1069  std::cout << "[LineSearch]: Best control found at alpha: " << alphaBest_ << ", with " << std::endl;
1070  std::cout << "[LineSearch]: Cost:\t" << intermediateCostBest_ + finalCostBest_ << std::endl;
1071  std::cout << "[LineSearch]: Defect:\t" << d_norm_ << std::endl;
1072  std::cout << "[LineSearch]: err box constr:\t" << e_box_norm_ << std::endl;
1073  std::cout << "[LineSearch]: err gen constr:\t" << e_gen_norm_ << std::endl;
1074  }
1075 
1076  if (alphaBest_ == 0.0)
1077  {
1079  {
1080  std::cout << "WARNING: No better control found during line search. Converged." << std::endl;
1081  }
1082  return false;
1083  }
1084  }
1085 
1086  if ((fabs((lowestCostPrevious - lowestCost_) / lowestCostPrevious)) > settings_.min_cost_improvement)
1087  {
1088  return true;
1089  }
1090 
1092  return true;
1093 
1094  if (settings_.debugPrint)
1095  {
1096  std::cout << "CONVERGED: Cost last iteration: " << lowestCostPrevious << ", current cost: " << lowestCost_
1097  << std::endl;
1098  std::cout << "CONVERGED: Cost improvement ratio was: "
1099  << fabs(lowestCostPrevious - lowestCost_) / lowestCostPrevious
1100  << "x, which is lower than convergence criteria: " << settings_.min_cost_improvement << std::endl;
1101  }
1102  return false;
1103 }
1104 
1105 
1106 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1108  const scalar_t alpha,
1113  scalar_t& intermediateCost,
1114  scalar_t& finalCost,
1115  scalar_t& defectNorm,
1116  scalar_t& e_box_norm,
1117  scalar_t& e_gen_norm,
1118  StateSubsteps& substepsX,
1119  ControlSubsteps& substepsU,
1120  std::atomic_bool* terminationFlag) const
1121 {
1122  intermediateCost = std::numeric_limits<scalar_t>::max();
1123  finalCost = std::numeric_limits<scalar_t>::max();
1124  defectNorm = std::numeric_limits<scalar_t>::max();
1125  e_box_norm = 0.0;
1126  e_gen_norm = 0.0;
1127 
1128  if (terminationFlag && *terminationFlag)
1129  return;
1130 
1131  // update feedforward with weighting alpha
1132  u_alpha = delta_u_ff_ * alpha + u_ff_prev_;
1133 
1134  // update state decision variables with weighting alpha
1135  x_alpha = delta_x_ * alpha + x_prev_;
1136 
1137  // update x_lqr reference
1139 
1140  if (terminationFlag && *terminationFlag)
1141  return;
1142 
1143  bool dynamicsGood;
1144 
1145  dynamicsGood = rolloutShotsSingleThreaded(threadId, 0 /*first index*/, K_ - 1 /*last index*/, u_alpha, x_alpha,
1146  x_ref_lqr, x_shot_alpha, defects_recorded, substepsX, substepsU, terminationFlag);
1147 
1148  if (terminationFlag && *terminationFlag)
1149  return;
1150 
1152  if (dynamicsGood)
1153  {
1155  defectNorm = computeDefectsNorm<1>(defects_recorded);
1156 
1157  if (terminationFlag && *terminationFlag)
1158  return;
1159 
1160  computeCostsOfTrajectory(threadId, x_alpha, u_alpha, intermediateCost, finalCost);
1161 
1162  if (terminationFlag && *terminationFlag)
1163  return;
1164 
1165  // compute constraint violations specific to this alpha
1166  if ((inputBoxConstraints_[threadId] != nullptr) | (stateBoxConstraints_[threadId] != nullptr))
1167  computeBoxConstraintErrorOfTrajectory(threadId, x_alpha, u_alpha, e_box_norm);
1168 
1169  if (terminationFlag && *terminationFlag)
1170  return;
1171 
1172  if (generalConstraints_[threadId] != nullptr)
1173  computeGeneralConstraintErrorOfTrajectory(threadId, x_alpha, u_alpha, e_gen_norm);
1174  }
1175  else
1176  {
1177  if (settings_.debugPrint)
1178  {
1179  std::string msg = std::string("dynamics not good, thread: ") + std::to_string(threadId);
1180  std::cout << msg << std::endl;
1181  }
1182  }
1183 }
1184 
1185 
1186 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1188  const SCALAR intermediateCost,
1189  const SCALAR finalCost,
1190  const SCALAR defectNorm,
1191  const SCALAR e_box_norm,
1192  const SCALAR e_gen_norm,
1193  const SCALAR lowestMeritPrevious,
1194  SCALAR& new_merit)
1195 {
1197  {
1198  case LineSearchSettings::TYPE::SIMPLE:
1199  {
1200  new_merit = intermediateCost + finalCost + settings_.meritFunctionRho * defectNorm +
1201  settings_.meritFunctionRhoConstraints * (e_box_norm + e_gen_norm);
1202 
1203  if ((lowestMeritPrevious - new_merit > 0.0) && !std::isnan(new_merit))
1204  {
1205  return true;
1206  }
1207 
1208  break;
1209  }
1210  case LineSearchSettings::TYPE::ARMIJO:
1211  {
1212  new_merit = intermediateCost + finalCost + settings_.meritFunctionRho * defectNorm +
1213  settings_.meritFunctionRhoConstraints * (e_box_norm + e_gen_norm);
1214 
1215  if (std::isnan(new_merit))
1216  return false;
1217 
1218  const ControlVectorArray& lv = lqocSolver_->get_lv();
1219 
1220  SCALAR Delta1 = 0;
1221  SCALAR Delta2 = 0;
1222  for (int i = 0; i < K_; i++)
1223  {
1224  // the expected decrease can sometimes become negative and allow an overall increase of cost - account for that below
1225  Delta1 += (lv[i].transpose() * lqocProblem_->rv_[i])(0);
1226  Delta2 += (lv[i].transpose() * lqocProblem_->R_[i] * lv[i])(0);
1227  }
1228 
1229  SCALAR expCostDecr = alpha * (Delta1 + alpha * 0.5 * Delta2);
1230 
1231  if ((lowestMeritPrevious - new_merit) >= (settings_.lineSearchSettings.armijo_parameter * expCostDecr) &&
1232  ((lowestMeritPrevious - new_merit) >= 0.0))
1233  {
1234  return true;
1235  }
1236 
1237  break;
1238  }
1239  case LineSearchSettings::TYPE::GOLDSTEIN:
1240  {
1241  throw std::runtime_error("Goldstein conditions not completed yet, use Armijo for now.");
1242 
1243  new_merit = intermediateCost + finalCost + settings_.meritFunctionRho * defectNorm +
1244  settings_.meritFunctionRhoConstraints * (e_box_norm + e_gen_norm);
1245 
1246  if (std::isnan(new_merit))
1247  return false;
1248 
1249  const ControlVectorArray& lv = lqocSolver_->get_lv();
1250 
1251  SCALAR Delta1 = 0;
1252  SCALAR Delta2 = 0;
1253  for (int i = 0; i < K_; i++)
1254  {
1255  // the expected decrease can sometimes become negative and allow an overall increase of cost - account for that below
1256  Delta1 += (lv[i].transpose() * lqocProblem_->rv_[i])(0);
1257  Delta2 += (lv[i].transpose() * lqocProblem_->R_[i] * lv[i])(0);
1258  }
1259 
1260  SCALAR expCostDecr = alpha * (Delta1 + alpha * 0.5 * Delta2);
1261 
1262  if (((lowestMeritPrevious - new_merit) >= (settings_.lineSearchSettings.armijo_parameter * expCostDecr)) &&
1263  ((lowestMeritPrevious - new_merit) <=
1264  ((1 - settings_.lineSearchSettings.armijo_parameter) * expCostDecr)))
1265  {
1266  return true;
1267  }
1268 
1269  break;
1270  }
1271  default:
1272  throw std::runtime_error("Invalid line search type in acceptStep()");
1273  };
1274 
1275  return false;
1276 }
1277 
1278 
1279 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1281 {
1282  lqpCounter_++;
1283 
1284  // if solver is HPIPM, there's nothing to prepare
1285  if (settings_.lqocp_solver == Settings_t::LQOCP_SOLVER::HPIPM_SOLVER)
1286  {
1287  // do nothing
1288  }
1289  // if solver is GNRiccati - we iterate backward up to the first stage
1290  else if (settings_.lqocp_solver == Settings_t::LQOCP_SOLVER::GNRICCATI_SOLVER)
1291  {
1292  lqocSolver_->setProblem(lqocProblem_);
1293 
1294  //iterate backward up to first stage
1295  for (int i = this->lqocProblem_->getNumberOfStages() - 1; i >= static_cast<int>(startIndex); i--)
1296  lqocSolver_->solveSingleStage(i);
1297  }
1298  else
1299  throw std::runtime_error("unknown solver type in prepareSolveLQProblem()");
1300 }
1301 
1302 
1303 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1305 {
1306  lqpCounter_++;
1307 
1308  // if solver is HPIPM, solve the full problem
1309  if (settings_.lqocp_solver == Settings_t::LQOCP_SOLVER::HPIPM_SOLVER)
1310  {
1312  }
1313  else if (settings_.lqocp_solver == Settings_t::LQOCP_SOLVER::GNRICCATI_SOLVER)
1314  {
1315  lqocSolver_->setProblem(lqocProblem_);
1316 
1317  for (int i = endIndex; i >= 0; i--)
1318  lqocSolver_->solveSingleStage(i);
1319 
1320  lqocSolver_->computeStatesAndControls();
1321  }
1322  else
1323  throw std::runtime_error("unknown solver type in finishSolveLQProblem()");
1324 }
1325 
1326 
1327 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1329 {
1330  lqpCounter_++;
1331 
1332  lqocSolver_->setProblem(lqocProblem_);
1333 
1334  lqocSolver_->solve();
1335 }
1336 
1337 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1339 {
1343 }
1344 
1345 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1347  StateMatrixArray& A,
1349  StateVectorArray& b)
1350 {
1351  A = lqocProblem_->A_;
1352  B = lqocProblem_->B_;
1353  b = lqocProblem_->b_;
1354 }
1355 
1356 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1359 {
1360  policy_.update(x_, u_ff_, L_, t_);
1361  return policy_;
1362 }
1363 
1364 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1366 {
1367  firstRollout_ = true;
1368  iteration_ = 0;
1369  d_norm_ = std::numeric_limits<scalar_t>::infinity();
1370  lx_norm_ = std::numeric_limits<scalar_t>::infinity();
1371  lu_norm_ = std::numeric_limits<scalar_t>::infinity();
1372  intermediateCostBest_ = std::numeric_limits<scalar_t>::infinity();
1373  finalCostBest_ = std::numeric_limits<scalar_t>::infinity();
1374  intermediateCostPrevious_ = std::numeric_limits<scalar_t>::infinity();
1375  finalCostPrevious_ = std::numeric_limits<scalar_t>::infinity();
1376  resetDefects();
1377 }
1378 
1379 
1380 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1382 {
1383  L_.setConstant(core::FeedbackMatrix<STATE_DIM, CONTROL_DIM, SCALAR>::Zero()); // TODO should eventually go away
1384  x_ref_lqr_ = x_;
1385 
1386  // extract the quantities required to update the solution candidate, depending on solver settings
1387  /*
1388  * case: GNMS: compute and retrieve dx, du
1389  * case: GNMS(M): compute and retrieve dx, du
1390  * case: Classical (open-loop) Single Shooting: compute and retrieve dx, du;
1391  * case: iLQR: compute and retrieve lv, L
1392  * case: Multiple-Shooting-iLQR: compute and retrieve dx, lv, L
1393  * case: Closed-loop Single Shooting: compute and retrieve dx, du, L
1394  * case: Closed-loop GNMS(M): compute and retrieve dx, du, L
1395  */
1396  switch (settings_.nlocp_algorithm)
1397  {
1398  case NLOptConSettings::NLOCP_ALGORITHM::GNMS:
1399  case NLOptConSettings::NLOCP_ALGORITHM::GNMS_M_OL:
1400  case NLOptConSettings::NLOCP_ALGORITHM::SS_OL:
1401  {
1402  lqocSolver_->computeStatesAndControls();
1403  delta_u_ff_ = lqocSolver_->getSolutionControl();
1404  delta_x_ = lqocSolver_->getSolutionState();
1406  break;
1407  }
1408  case NLOptConSettings::NLOCP_ALGORITHM::ILQR:
1409  {
1410  lqocSolver_->compute_lv();
1411  delta_u_ff_ = lqocSolver_->get_lv();
1412  lqocSolver_->computeFeedbackMatrices();
1413  L_ = lqocSolver_->getSolutionFeedback();
1416  break;
1417  }
1418  case NLOptConSettings::NLOCP_ALGORITHM::MS_ILQR:
1419  {
1420  lqocSolver_->computeStatesAndControls();
1421  delta_x_ = lqocSolver_->getSolutionState();
1423  lqocSolver_->compute_lv();
1424  delta_u_ff_ = lqocSolver_->get_lv();
1425  lqocSolver_->computeFeedbackMatrices();
1426  L_ = lqocSolver_->getSolutionFeedback();
1427  break;
1428  }
1429  case NLOptConSettings::NLOCP_ALGORITHM::SS_CL:
1430  case NLOptConSettings::NLOCP_ALGORITHM::GNMS_M_CL:
1431  {
1432  lqocSolver_->computeStatesAndControls();
1433  delta_u_ff_ = lqocSolver_->getSolutionControl();
1434  delta_x_ = lqocSolver_->getSolutionState();
1436  lqocSolver_->computeFeedbackMatrices();
1437  L_ = lqocSolver_->getSolutionFeedback();
1438  break;
1439  }
1440  default:
1441  throw std::runtime_error("Unknown NLOC Algorithm type given in settings.");
1442  }
1443 }
1444 
1445 
1446 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1448 {
1449  alphaBest_ = 1.0;
1450 
1451  x_ += delta_x_;
1452  u_ff_ += delta_u_ff_;
1454 }
1455 
1456 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1458  const std::string& fileName)
1459 {
1460  summaryAllIterations_.logToMatlab(fileName);
1461 }
1462 
1463 
1464 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1467 {
1468  return summaryAllIterations_;
1469 }
1470 
1471 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1473 {
1474  d_.setConstant(state_vector_t::Zero());
1475 }
1476 
1477 
1478 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1480 {
1481  d_norm_ = computeDefectsNorm<1>(d_);
1482 }
1483 
1484 
1485 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1487 {
1488  return iteration_;
1489 }
1490 
1491 
1492 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1494 {
1495  bool success =
1496  rolloutSingleShot(settings_.nThreads, 0, u_ff_, x_, x_prev_, xShot_, *this->substepsX_, *this->substepsU_);
1497  x_prev_ = x_;
1498  u_ff_prev_ = u_ff_;
1499  firstRollout_ = false;
1500  return success;
1501 }
1502 
1503 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1506 {
1507  return t_;
1508 }
1509 
1510 
1511 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1513 {
1514  return configured_;
1515 }
1516 
1517 
1518 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1520 {
1521  return initialized_;
1522 }
1523 
1524 
1525 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1527 {
1528  return d_norm_;
1529 }
1530 
1531 
1532 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1534 {
1535  return true; // TODO this is currently meaningless
1536 }
1537 
1538 
1539 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1540 std::vector<
1543 {
1544  return systemInterface_->getNonlinearSystemsInstances();
1545 }
1546 
1547 
1548 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1549 const std::vector<
1552 {
1553  return systemInterface_->getNonlinearSystemsInstances();
1554 }
1555 
1556 
1557 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1558 std::vector<
1561 {
1562  return systemInterface_->getLinearSystemsInstances();
1563 }
1564 
1565 
1566 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1567 const std::vector<
1570 {
1571  return systemInterface_->getLinearSystemsInstances();
1572 }
1573 
1574 
1575 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1576 std::vector<typename NLOCBackendBase<STATE_DIM, CONTROL_DIM, P_DIM, V_DIM, SCALAR, CONTINUOUS>::OptConProblem_t::
1577  CostFunctionPtr_t>&
1579 {
1580  return costFunctions_;
1581 }
1582 
1583 
1584 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1585 const std::vector<typename NLOCBackendBase<STATE_DIM, CONTROL_DIM, P_DIM, V_DIM, SCALAR, CONTINUOUS>::OptConProblem_t::
1586  CostFunctionPtr_t>&
1588 {
1589  return costFunctions_;
1590 }
1591 
1592 
1593 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1594 std::vector<typename NLOCBackendBase<STATE_DIM, CONTROL_DIM, P_DIM, V_DIM, SCALAR, CONTINUOUS>::OptConProblem_t::
1595  ConstraintPtr_t>&
1597 {
1598  return inputBoxConstraints_;
1599 }
1600 
1601 
1602 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1603 const std::vector<typename NLOCBackendBase<STATE_DIM, CONTROL_DIM, P_DIM, V_DIM, SCALAR, CONTINUOUS>::OptConProblem_t::
1604  ConstraintPtr_t>&
1606 {
1607  return inputBoxConstraints_;
1608 }
1609 
1610 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1611 std::vector<typename NLOCBackendBase<STATE_DIM, CONTROL_DIM, P_DIM, V_DIM, SCALAR, CONTINUOUS>::OptConProblem_t::
1612  ConstraintPtr_t>&
1614 {
1615  return stateBoxConstraints_;
1616 }
1617 
1618 
1619 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1620 const std::vector<typename NLOCBackendBase<STATE_DIM, CONTROL_DIM, P_DIM, V_DIM, SCALAR, CONTINUOUS>::OptConProblem_t::
1621  ConstraintPtr_t>&
1623 {
1624  return stateBoxConstraints_;
1625 }
1626 
1627 
1628 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1629 std::vector<typename NLOCBackendBase<STATE_DIM, CONTROL_DIM, P_DIM, V_DIM, SCALAR, CONTINUOUS>::OptConProblem_t::
1630  ConstraintPtr_t>&
1632 {
1633  return generalConstraints_;
1634 }
1635 
1636 
1637 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1638 const std::vector<typename NLOCBackendBase<STATE_DIM, CONTROL_DIM, P_DIM, V_DIM, SCALAR, CONTINUOUS>::OptConProblem_t::
1639  ConstraintPtr_t>&
1641 {
1642  return generalConstraints_;
1643 }
1644 
1645 
1646 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1648 {
1649  return K_ * settings_.dt;
1650 }
1651 
1652 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1654 {
1655  return K_;
1656 }
1657 
1658 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1660 {
1662  return K_;
1663  else
1664  return settings_.K_shot;
1665 }
1666 
1667 template <size_t STATE_DIM, size_t CONTROL_DIM, size_t P_DIM, size_t V_DIM, typename SCALAR, bool CONTINUOUS>
1670 {
1671  return settings_;
1672 }
1673 
1674 } // namespace optcon
1675 } // namespace ct
LineSearchSettings lineSearchSettings
number of threads for eigen parallelization (applies both to MP and ST) Note. in order to activate Ei...
Definition: NLOptConSettings.hpp:275
ct::core::StateControlMatrixArray< STATE_DIM, CONTROL_DIM, SCALAR > B_
Definition: LQOCProblem.hpp:207
StateVectorArray xShot_
state array variables
Definition: NLOCBackendBase.hpp:564
std::vector< typename OptConProblem_t::DynamicsPtr_t > & getNonlinearSystemsInstances()
Direct accessor to the system instances.
Definition: NLOCBackendBase-impl.hpp:1542
void computeCostsOfTrajectory(size_t threadId, const core::StateVectorArray< STATE_DIM, SCALAR > &x_local, const core::ControlVectorArray< CONTROL_DIM, SCALAR > &u_local, scalar_t &intermediateCost, scalar_t &finalCost) const
Compute cost for a given set of state and input trajectory.
Definition: NLOCBackendBase-impl.hpp:572
void setInputBoxConstraintsForLQOCProblem()
sets the box constraints for the entire time horizon including terminal stage
Definition: NLOCBackendBase-impl.hpp:727
void computeSingleDefect(size_t k, const StateVectorArray &x_local, const StateVectorArray &xShot, StateVectorArray &d) const
computes the defect between shot and trajectory
Definition: NLOCBackendBase-impl.hpp:556
StateVectorArray delta_x_ref_lqr_
pointer to state increment
Definition: NLOCBackendBase.hpp:575
interface class for optimal control algorithms
Definition: OptconDiscreteSystemInterface.h:21
LQOCP_SOLVER lqocp_solver
which nonlinear optimal control algorithm is to be used
Definition: NLOptConSettings.hpp:259
void executeLQApproximation(size_t threadId, size_t k)
Computes the linearized Dynamics and quadratic cost approximation at a specific point of the trajecto...
Definition: NLOCBackendBase-impl.hpp:685
double maxDefectSum
minimum cost improvement between two interations to assume convergence
Definition: NLOptConSettings.hpp:266
SCALAR getTimeHorizon()
Definition: NLOCBackendBase-impl.hpp:1647
std::vector< typename OptConProblem_t::ConstraintPtr_t > & getStateBoxConstraintsInstances()
Definition: NLOCBackendBase-impl.hpp:1613
systemInterfacePtr_t systemInterface_
pointer to instance of the system interface
Definition: NLOCBackendBase.hpp:603
ct::core::StateMatrixArray< STATE_DIM, SCALAR > A_
affine, time-varying system dynamics in discrete time
Definition: LQOCProblem.hpp:206
bool printSummary
Definition: NLOptConSettings.hpp:278
ct::core::ControlMatrixArray< CONTROL_DIM, SCALAR > R_
Definition: LQOCProblem.hpp:219
std::string loggingPrefix
the solver for the linear-quadratic optimal control problem
Definition: NLOptConSettings.hpp:260
ct::core::FeedbackArray< STATE_DIM, CONTROL_DIM, SCALAR > P_
LQ approximation of the cross terms of the cost function.
Definition: LQOCProblem.hpp:222
constr_control_jac_array_t D_
Definition: LQOCProblem.hpp:250
void computeDefectsNorm()
update the nominal defects
Definition: NLOCBackendBase-impl.hpp:1479
std::enable_if< std::is_same< T, ContinuousOptConProblem< STATE_DIM, CONTROL_DIM, SCALAR > >::value, systemInterfacePtr_t >::type createSystemInterface(const OptConProblem_t &optConProblem, const Settings_t &settings)
Definition: NLOCBackendBase-impl.hpp:105
size_t nThreadsEigen
number of threads, for MP version
Definition: NLOptConSettings.hpp:274
double armijo_parameter
Definition: NLOptConSettings.hpp:65
double dt
Eigenvalue correction factor for Hessian regularization.
Definition: NLOptConSettings.hpp:262
void changeInitialState(const core::StateVector< STATE_DIM, SCALAR > &x0)
Change the initial state for the optimal control problem.
Definition: NLOCBackendBase-impl.hpp:238
int K_
Definition: NLOCBackendBase.hpp:561
StateVectorArray x_ref_lqr_
state array from previous iteration
Definition: NLOCBackendBase.hpp:567
scalar_t lowestCost_
Definition: NLOCBackendBase.hpp:588
TYPE type
Definition: NLOptConSettings.hpp:58
scalar_t finalCostBest_
Definition: NLOCBackendBase.hpp:587
bool rolloutSingleShot(const size_t threadId, const size_t k, ControlVectorArray &u_ff_local, StateVectorArray &x_local, const StateVectorArray &x_ref_lqr, StateVectorArray &xShot, StateSubsteps &substepsX, ControlSubsteps &substepsU, std::atomic_bool *terminationFlag=nullptr) const
integrate the individual shots
Definition: NLOCBackendBase-impl.hpp:436
bool closedLoopShooting() const
return if this is a closed-loop shooting algorithm (or not)
Definition: NLOptConSettings.hpp:303
ct::core::StateVectorArray< STATE_DIM, SCALAR > b_
Definition: LQOCProblem.hpp:208
int getNumSteps()
Definition: NLOCBackendBase-impl.hpp:1653
std::shared_ptr< LQOCProblem< STATE_DIM, CONTROL_DIM, SCALAR > > lqocProblem_
shared pointer to the linear-quadratic optimal control problem that is constructed by NLOC ...
Definition: NLOCBackendBase.hpp:597
virtual void rolloutShots(size_t firstIndex, size_t lastIndex)=0
integrates the specified shots and computes the corresponding defects
size_t iteration_
Definition: NLOCBackendBase.hpp:555
virtual void solveFullLQProblem()
Definition: NLOCBackendBase-impl.hpp:1328
StateVectorArray d_
rolled-out state (at the end of a time step forward)
Definition: NLOCBackendBase.hpp:565
void reset()
Definition: NLOCBackendBase-impl.hpp:1365
std::vector< int > ng_
number of general inequality constraints
Definition: LQOCProblem.hpp:252
void computeLinearizedConstraints(size_t threadId, size_t k)
Computes the linearized general constraints at a specific point of the trajectory.
Definition: NLOCBackendBase-impl.hpp:790
bool debugPrint
Definition: NLOptConSettings.hpp:66
StateVectorArray x_
the time trajectory
Definition: NLOCBackendBase.hpp:563
bool isInitialized()
Definition: NLOCBackendBase-impl.hpp:1519
bool debugPrint
Definition: NLOptConSettings.hpp:277
void changeGeneralConstraints(const typename OptConProblem_t::ConstraintPtr_t &con)
Change the general constraints.
Definition: NLOCBackendBase-impl.hpp:322
double meritFunctionRhoConstraints
trade off between internal (defect)constraint violation and cost
Definition: NLOptConSettings.hpp:268
ct::core::tpl::TimeArray< SCALAR > t_
the number of stages in the overall OptConProblem
Definition: NLOCBackendBase.hpp:562
SCALAR lu_norm_
sum of the norms of state update
Definition: NLOCBackendBase.hpp:584
FeedbackArray L_
feed forward controls from previous iteration
Definition: NLOCBackendBase.hpp:571
void setInitialGuess(const Policy_t &initialGuess)
Definition: NLOCBackendBase-impl.hpp:126
const DiscreteArray< FeedbackMatrix< STATE_DIM, CONTROL_DIM, SCALAR > > & K() const
void setConstant(const T &data)
void setStateBoxConstraintsForLQOCProblem()
Definition: NLOCBackendBase-impl.hpp:752
void changeLinearSystem(const typename OptConProblem_t::LinearPtr_t &lin)
Change the linear system.
Definition: NLOCBackendBase-impl.hpp:364
int getNumStepsPerShot() const
Definition: NLOCBackendBase-impl.hpp:1659
std::vector< StateVectorArrayPtr, Eigen::aligned_allocator< StateVectorArrayPtr > > StateSubsteps
Definition: NLOCBackendBase.hpp:73
const core::ControlTrajectory< CONTROL_DIM, SCALAR > getControlTrajectory() const
Definition: NLOCBackendBase-impl.hpp:980
bool isSingleShooting() const
return if this is a single-shooting algorithm (or not)
Definition: NLOptConSettings.hpp:306
SCALAR getCost() const
return the cost of the solution of the current iteration
Definition: NLOCBackendBase-impl.hpp:1003
virtual ~NLOCBackendBase()
Definition: NLOCBackendBase-impl.hpp:97
StateVectorArray x_prev_
defects in between end of rollouts and subsequent state decision vars
Definition: NLOCBackendBase.hpp:566
double min_cost_improvement
duration of a shot as an integer multiple of dt
Definition: NLOptConSettings.hpp:265
const DiscreteArray< state_vector_t > & x_ref() const
ct::core::StateMatrixArray< STATE_DIM, SCALAR > Q_
Definition: LQOCProblem.hpp:215
std::vector< typename OptConProblem_t::ConstraintPtr_t > & getInputBoxConstraintsInstances()
Direct accessor to the box constraint instances.
Definition: NLOCBackendBase-impl.hpp:1596
ControlVectorArray u_ff_prev_
feed forward controls
Definition: NLOCBackendBase.hpp:570
Definition: NLOCResults.hpp:18
std::vector< typename OptConProblem_t::ConstraintPtr_t > generalConstraints_
Definition: NLOCBackendBase.hpp:612
constr_vec_array_t d_ub_
general constraint upper bound
Definition: LQOCProblem.hpp:247
void extractSolution()
extract relevant quantities for the following rollout/solution update step from the LQ solver ...
Definition: NLOCBackendBase-impl.hpp:1381
const double dt
Definition: LQOCSolverTiming.cpp:18
std::shared_ptr< LQOCSolver< STATE_DIM, CONTROL_DIM, SCALAR > > lqocSolver_
shared pointer to the linear-quadratic optimal control solver, that solves above LQOCP ...
Definition: NLOCBackendBase.hpp:600
NLOCP_ALGORITHM nlocp_algorithm
Definition: NLOptConSettings.hpp:258
void changeCostFunction(const typename OptConProblem_t::CostFunctionPtr_t &cf)
Change the cost function.
Definition: NLOCBackendBase-impl.hpp:249
virtual void prepareSolveLQProblem(size_t startIndex)
Definition: NLOCBackendBase-impl.hpp:1280
StateVectorArray delta_x_
pointer to control increment
Definition: NLOCBackendBase.hpp:574
std::vector< typename OptConProblem_t::LinearPtr_t > & getLinearSystemsInstances()
Direct accessor to the linear system instances.
Definition: NLOCBackendBase-impl.hpp:1560
bool rolloutShotsSingleThreaded(size_t threadId, size_t firstIndex, size_t lastIndex, ControlVectorArray &u_ff_local, StateVectorArray &x_local, const StateVectorArray &x_ref_lqr, StateVectorArray &xShot, StateVectorArray &d, StateSubsteps &substepsX, ControlSubsteps &substepsU, std::atomic_bool *terminationFlag=nullptr) const
do a single threaded rollout and defect computation of the shots - useful for line-search ...
Definition: NLOCBackendBase-impl.hpp:524
bool firstRollout_
Definition: NLOCBackendBase.hpp:557
double meritFunctionRho
maximum sum of squared defects (assume covergence if lower than this number)
Definition: NLOptConSettings.hpp:267
Settings for the NLOptCon algorithm.
Definition: NLOptConSettings.hpp:198
std::conditional< CONTINUOUS, ContinuousOptConProblem< STATE_DIM, CONTROL_DIM, SCALAR >, DiscreteOptConProblem< STATE_DIM, CONTROL_DIM, SCALAR > >::type OptConProblem_t
Definition: NLOCBackendBase.hpp:62
CppAD::AD< CppAD::cg::CG< double > > SCALAR
bool logToMatlab
Definition: NLOptConSettings.hpp:280
SCALAR getTotalDefect() const
return the sum of the L2-norm of the defects along the solution candidate
Definition: NLOCBackendBase-impl.hpp:1526
NLOCBackendBase(const OptConProblem_t &optConProblem, const Settings_t &settings)
Definition: NLOCBackendBase-impl.hpp:13
interface class for optimal control algorithms
Definition: OptconContinuousSystemInterface.h:28
size_t lqpCounter_
a counter used to identify lqp problems in derived classes, i.e. for thread management in MP ...
Definition: NLOCBackendBase.hpp:615
const DiscreteArray< control_vector_t > & uff() const
Settings_t settings_
Definition: NLOCBackendBase.hpp:559
Defines a Linear-Quadratic Optimal Control Problem, which is optionally constrained.
Definition: LQOCProblem.hpp:57
bool testConsistency()
Definition: NLOCBackendBase-impl.hpp:1533
void logToMatlab(const size_t &iteration)
Export all functions to matlab workspace.
Definition: NLOCBackendBase-impl.hpp:895
virtual void configure(const Settings_t &settings)
configure the solver
Definition: NLOCBackendBase-impl.hpp:385
void executeLineSearch(const size_t threadId, const scalar_t alpha, ct::core::StateVectorArray< STATE_DIM, SCALAR > &x_recorded, ct::core::StateVectorArray< STATE_DIM, SCALAR > &x_shot_recorded, ct::core::StateVectorArray< STATE_DIM, SCALAR > &defects_recorded, ct::core::ControlVectorArray< CONTROL_DIM, SCALAR > &u_recorded, scalar_t &intermediateCost, scalar_t &finalCost, scalar_t &defectNorm, scalar_t &e_box_norm, scalar_t &e_gen_norm, StateSubsteps &substepsX, ControlSubsteps &substepsU, std::atomic_bool *terminationFlag=nullptr) const
Check if controller with particular alpha is better.
Definition: NLOCBackendBase-impl.hpp:1107
for i
Definition: mpc_unittest_plotting.m:14
constr_state_jac_array_t C_
linear general constraint matrices
Definition: LQOCProblem.hpp:249
int K_sim
sampling time for the control input (seconds)
Definition: NLOptConSettings.hpp:263
ControlVectorArray u_ff_
reference for lqr
Definition: NLOCBackendBase.hpp:569
std::vector< ControlVectorArrayPtr, Eigen::aligned_allocator< ControlVectorArrayPtr > > ControlSubsteps
Definition: NLOCBackendBase.hpp:76
const Settings_t & getSettings() const
get the current SLQsolver settings
Definition: NLOCBackendBase-impl.hpp:1669
std::shared_ptr< systemInterface_t > systemInterfacePtr_t
Definition: NLOCBackendBase.hpp:80
Definition: GNRiccatiSolver.hpp:22
std::vector< typename OptConProblem_t::CostFunctionPtr_t > costFunctions_
Definition: NLOCBackendBase.hpp:609
ControlVectorArray delta_u_ff_
time-varying lqr feedback
Definition: NLOCBackendBase.hpp:573
void resetDefects()
reset all defects to zero
Definition: NLOCBackendBase-impl.hpp:1472
constr_vec_array_t d_lb_
general constraint lower bound
Definition: LQOCProblem.hpp:245
const Policy_t & getSolution()
Definition: NLOCBackendBase-impl.hpp:1358
SCALAR scalar_t
Definition: NLOCBackendBase.hpp:98
virtual SCALAR performLineSearch()=0
performLineSearch: execute the line search, possibly with different threading schemes ...
scalar_t finalCostPrevious_
Definition: NLOCBackendBase.hpp:592
bool acceptStep(const SCALAR alpha, const SCALAR intermediateCost, const SCALAR finalCost, const SCALAR defectNorm, const SCALAR e_box_norm, const SCALAR e_gen_norm, const SCALAR lowestMeritPrevious, SCALAR &new_merit)
in case of line-search compute new merit and check if to accept step. Returns true if accept step ...
Definition: NLOCBackendBase-impl.hpp:1187
scalar_t alphaBest_
Definition: NLOCBackendBase.hpp:594
int computeK(double timeHorizon) const
log to matlab (true/false)
Definition: NLOptConSettings.hpp:290
StateSubstepsPtr substepsX_
state array from previous iteration
Definition: NLOCBackendBase.hpp:577
void update(const DiscreteArray< state_vector_t > &x_ref, const DiscreteArray< control_vector_t > &uff, const DiscreteArray< FeedbackMatrix< STATE_DIM, CONTROL_DIM, SCALAR >> &K, const tpl::TimeArray< SCALAR > &t)
lv
Definition: gnmsPlot.m:7
const SummaryAllIterations< SCALAR > & getSummary() const
Definition: NLOCBackendBase-impl.hpp:1466
NLOCBackendBase::Policy_t policy_
The policy. currently only for returning the result, should eventually replace L_ and u_ff_ (todo) ...
Definition: NLOCBackendBase.hpp:618
std::vector< typename OptConProblem_t::ConstraintPtr_t > stateBoxConstraints_
Definition: NLOCBackendBase.hpp:611
void retrieveLastAffineModel(StateMatrixArray &A, StateControlMatrixArray &B, StateVectorArray &b)
Retrieve Last Linearized Model.
Definition: NLOCBackendBase-impl.hpp:1346
virtual void finishSolveLQProblem(size_t endIndex)
Definition: NLOCBackendBase-impl.hpp:1304
ct::core::ControlVectorArray< CONTROL_DIM, SCALAR > rv_
LQ approximation of the pure control penalty.
Definition: LQOCProblem.hpp:218
SCALAR e_gen_norm_
sum of the norms of all box constraint violations
Definition: NLOCBackendBase.hpp:582
scalar_t intermediateCostBest_
sum of the norms of control update
Definition: NLOCBackendBase.hpp:586
SCALAR lx_norm_
sum of the norms of all general constraint violations
Definition: NLOCBackendBase.hpp:583
bool initialized_
Definition: NLOCBackendBase.hpp:552
ct::core::StateVectorArray< STATE_DIM, SCALAR > qv_
LQ approximation of the pure state penalty, including terminal state penalty.
Definition: LQOCProblem.hpp:214
const TimeArray & getTimeArray()
Definition: NLOCBackendBase-impl.hpp:1505
ControlSubstepsPtr substepsU_
state substeps recorded by integrator during rollouts
Definition: NLOCBackendBase.hpp:578
void computeBoxConstraintErrorOfTrajectory(size_t threadId, const ct::core::StateVectorArray< STATE_DIM, SCALAR > &x_local, const ct::core::ControlVectorArray< CONTROL_DIM, SCALAR > &u_local, scalar_t &e_tot) const
Compute box constraint violations for a given set of state and input trajectory.
Definition: NLOCBackendBase-impl.hpp:596
C++ implementation of GNMS.
Definition: NLOCBackendBase.hpp:48
void changeStateBoxConstraints(const typename OptConProblem_t::ConstraintPtr_t &con)
Change the state box constraints.
Definition: NLOCBackendBase-impl.hpp:299
void doFullStepUpdate()
simple full-step update for state and feedforward control (used for MPC-mode!)
Definition: NLOCBackendBase-impl.hpp:1447
void initializeCostToGo()
Initializes cost to go.
Definition: NLOCBackendBase-impl.hpp:819
void changeNonlinearSystem(const typename OptConProblem_t::DynamicsPtr_t &dyn)
Change the nonlinear system.
Definition: NLOCBackendBase-impl.hpp:270
bool recordSmallestEigenvalue
perform Hessian regularization by incrementing the eigenvalues by epsilon.
Definition: NLOptConSettings.hpp:271
bool isConfigured()
Definition: NLOCBackendBase-impl.hpp:1512
StateVector< state_dim > x0
Definition: ConstrainedNLOCTest.cpp:14
ct::core::ScalarArray< SCALAR > q_
constant term of in the LQ approximation of the cost function
Definition: LQOCProblem.hpp:211
std::vector< typename OptConProblem_t::CostFunctionPtr_t > & getCostFunctionInstances()
Direct accessor to the cost function instances.
Definition: NLOCBackendBase-impl.hpp:1578
void printSummary()
Print iteration summary.
Definition: NLOCBackendBase-impl.hpp:850
const bool verbose
Definition: ConstraintComparison.h:18
bool nominalRollout()
nominal rollout using default thread and member variables for the results. // todo maybe rename (init...
Definition: NLOCBackendBase-impl.hpp:1493
int nThreads
save the smallest eigenvalue of the Hessian
Definition: NLOptConSettings.hpp:272
void changeTimeHorizon(const SCALAR &tf)
Change the time horizon the solver operates on.
Definition: NLOCBackendBase-impl.hpp:229
std::vector< typename OptConProblem_t::ConstraintPtr_t > & getGeneralConstraintsInstances()
Direct accessor to the general constraints.
Definition: NLOCBackendBase-impl.hpp:1631
void changeInputBoxConstraints(const typename OptConProblem_t::ConstraintPtr_t &con)
Change the input box constraints.
Definition: NLOCBackendBase-impl.hpp:277
int K_shot
number of sub-integration-steps
Definition: NLOptConSettings.hpp:264
void logSummaryToMatlab(const std::string &fileName)
Definition: NLOCBackendBase-impl.hpp:1457
scalar_t intermediateCostPrevious_
costs of the previous iteration, required to determine convergence
Definition: NLOCBackendBase.hpp:591
bool configured_
Definition: NLOCBackendBase.hpp:553
std::vector< typename OptConProblem_t::ConstraintPtr_t > inputBoxConstraints_
Definition: NLOCBackendBase.hpp:610
void updateCosts()
compute costs of solution candidate
Definition: NLOCBackendBase-impl.hpp:1338
bool parametersOk() const
perform a quick check if the given NLOptCon settings fulfil minimum requirements
Definition: NLOptConSettings.hpp:349
SCALAR d_norm_
control substeps recorded by integrator during rollouts
Definition: NLOCBackendBase.hpp:580
bool lineSearch()
perform line-search and update controller
Definition: NLOCBackendBase-impl.hpp:1010
size_t & iteration()
return the current iteration number
Definition: NLOCBackendBase-impl.hpp:1486
void logInitToMatlab()
log the initial guess to Matlab
Definition: NLOCBackendBase-impl.hpp:946
void checkProblem()
check problem for consistency
Definition: NLOCBackendBase-impl.hpp:371
SCALAR e_box_norm_
sum of the norms of all defects (internal constraint)
Definition: NLOCBackendBase.hpp:581
ct::core::tpl::TimeArray< SCALAR > TimeArray
Definition: NLOCBackendBase.hpp:87
SummaryAllIterations< SCALAR > summaryAllIterations_
Definition: NLOCBackendBase.hpp:620
void computeGeneralConstraintErrorOfTrajectory(size_t threadId, const ct::core::StateVectorArray< STATE_DIM, SCALAR > &x_local, const ct::core::ControlVectorArray< CONTROL_DIM, SCALAR > &u_local, scalar_t &e_tot) const
Compute general constraint violations for a given set of state and input trajectory.
Definition: NLOCBackendBase-impl.hpp:647
const core::StateTrajectory< STATE_DIM, SCALAR > getStateTrajectory() const
Definition: NLOCBackendBase-impl.hpp:993