nmpc_fmpc
FmpcSolver.hpp
Go to the documentation of this file.
1 /* Author: Masaki Murooka */
2 
3 #include <chrono>
4 #include <fstream>
5 #include <iostream>
6 #include <limits>
7 
8 #include <nmpc_fmpc/MathUtils.h>
9 
10 #define CHECK_NAN(VAR, PRINT_PREFIX) \
11  if(VAR.array().isNaN().any() || VAR.array().isInf().any()) \
12  { \
13  if(print_level >= 3) \
14  { \
15  std::cout << PRINT_PREFIX << #VAR << " contains NaN or infinity: " << VAR.transpose() << std::endl; \
16  } \
17  return true; \
18  }
19 
20 namespace
21 {
22 template<class Clock>
23 double calcDuration(const std::chrono::time_point<Clock> & start_time, const std::chrono::time_point<Clock> & end_time)
24 {
25  return 1e3 * std::chrono::duration_cast<std::chrono::duration<double>>(end_time - start_time).count();
26 }
27 } // namespace
28 
29 namespace nmpc_fmpc
30 {
31 template<int StateDim, int InputDim, int IneqDim>
32 FmpcSolver<StateDim, InputDim, IneqDim>::Variable::Variable(int _horizon_steps) : horizon_steps(_horizon_steps)
33 {
34  x_list.resize(horizon_steps + 1);
35  u_list.resize(horizon_steps);
36  lambda_list.resize(horizon_steps + 1);
37  s_list.resize(horizon_steps);
38  nu_list.resize(horizon_steps);
39 }
40 
41 template<int StateDim, int InputDim, int IneqDim>
43  double _u,
44  double _lambda,
45  double _s,
46  double _nu)
47 {
48  for(auto & x : x_list)
49  {
50  x.setConstant(_x);
51  }
52  for(auto & u : u_list)
53  {
54  u.setConstant(_u);
55  }
56  for(auto & lambda : lambda_list)
57  {
58  lambda.setConstant(_lambda);
59  }
60  for(auto & s : s_list)
61  {
62  s.setConstant(_s);
63  }
64  for(auto & nu : nu_list)
65  {
66  nu.setConstant(_nu);
67  }
68 }
69 
70 template<int StateDim, int InputDim, int IneqDim>
72 {
73  for(auto & x : x_list)
74  {
75  CHECK_NAN(x, "[FMPC/Variable] ");
76  }
77  for(auto & u : u_list)
78  {
79  CHECK_NAN(u, "[FMPC/Variable] ");
80  }
81  for(auto & lambda : lambda_list)
82  {
83  CHECK_NAN(lambda, "[FMPC/Variable] ");
84  }
85  for(auto & s : s_list)
86  {
87  CHECK_NAN(s, "[FMPC/Variable] ");
88  }
89  for(auto & nu : nu_list)
90  {
91  CHECK_NAN(nu, "[FMPC/Variable] ");
92  }
93 
94  return false;
95 }
96 
97 template<int StateDim, int InputDim, int IneqDim>
98 FmpcSolver<StateDim, InputDim, IneqDim>::Coefficient::Coefficient(int state_dim, int input_dim, int ineq_dim)
99 {
100  A.resize(state_dim, state_dim);
101  B.resize(state_dim, input_dim);
102  C.resize(ineq_dim, state_dim);
103  D.resize(ineq_dim, input_dim);
104 
105  Lx.resize(state_dim);
106  Lu.resize(input_dim);
107  Lxx.resize(state_dim, state_dim);
108  Luu.resize(input_dim, input_dim);
109  Lxu.resize(state_dim, input_dim);
110 
111  x_bar.resize(state_dim);
112  g_bar.resize(ineq_dim);
113  Lx_bar.resize(state_dim);
114  Lu_bar.resize(input_dim);
115 
116  k.resize(input_dim);
117  K.resize(input_dim, state_dim);
118  s.resize(state_dim);
119  P.resize(state_dim, state_dim);
120 }
121 
122 template<int StateDim, int InputDim, int IneqDim>
124 {
125  Lx.resize(state_dim);
126  Lxx.resize(state_dim, state_dim);
127  Lx_bar.resize(state_dim);
128 
129  s.resize(state_dim);
130  P.resize(state_dim, state_dim);
131 }
132 
133 template<int StateDim, int InputDim, int IneqDim>
135 {
136  CHECK_NAN(A, "[FMPC/Coefficient] ");
137  CHECK_NAN(B, "[FMPC/Coefficient] ");
138  CHECK_NAN(C, "[FMPC/Coefficient] ");
139  CHECK_NAN(D, "[FMPC/Coefficient] ");
140  CHECK_NAN(Lx, "[FMPC/Coefficient] ");
141  CHECK_NAN(Lu, "[FMPC/Coefficient] ");
142  CHECK_NAN(Lxx, "[FMPC/Coefficient] ");
143  CHECK_NAN(Luu, "[FMPC/Coefficient] ");
144  CHECK_NAN(Lxu, "[FMPC/Coefficient] ");
145  CHECK_NAN(x_bar, "[FMPC/Coefficient] ");
146  CHECK_NAN(g_bar, "[FMPC/Coefficient] ");
147  CHECK_NAN(Lx_bar, "[FMPC/Coefficient] ");
148  CHECK_NAN(Lu_bar, "[FMPC/Coefficient] ");
149  CHECK_NAN(k, "[FMPC/Coefficient] ");
150  CHECK_NAN(K, "[FMPC/Coefficient] ");
151  CHECK_NAN(s, "[FMPC/Coefficient] ");
152  CHECK_NAN(P, "[FMPC/Coefficient] ");
153 
154  return false;
155 }
156 
157 template<int StateDim, int InputDim, int IneqDim>
159  double current_t,
160  const StateDimVector & current_x,
161  const Variable & initial_variable)
162 {
163  auto start_time = std::chrono::system_clock::now();
164 
165  // Initialize variables
166  current_t_ = current_t;
167  current_x_ = current_x;
168  variable_ = initial_variable;
170 
171  // Initialize complementarity variables
173  {
174  constexpr double initial_barrier_eps = 1e-4;
175  constexpr double complementary_variable_margin_rate = 1e-2;
176  constexpr double complementary_variable_min = 1e-2;
177 
178  barrier_eps_ = initial_barrier_eps;
179  for(int i = 0; i < config_.horizon_steps; i++)
180  {
181  double t = current_t_ + i * problem_->dt();
182  variable_.s_list[i] = (1.0 + complementary_variable_margin_rate)
183  * (-1 * problem_->ineqConst(t, variable_.x_list[i], variable_.u_list[i]))
184  .cwiseMax(complementary_variable_min);
185  variable_.nu_list[i] = (1.0 + complementary_variable_margin_rate)
186  * (barrier_eps_ * variable_.s_list[i].cwiseInverse()).cwiseMax(complementary_variable_min);
187  }
188  }
189 
190  // Check variable_
191  checkVariable();
192 
193  // Setup delta_variable_
195  {
198  }
199 
200  // Setup coeff_list_
201  if constexpr(InputDim == Eigen::Dynamic || IneqDim == Eigen::Dynamic)
202  {
203  coeff_list_.clear();
204  for(int i = 0; i < config_.horizon_steps; i++)
205  {
206  double t = current_t_ + i * problem_->dt();
207  coeff_list_.emplace_back(problem_->stateDim(), problem_->inputDim(t), problem_->ineqDim(t));
208  }
209  }
210  else
211  {
212  // This assumes that the dimension is fixed, but it is efficient because it preserves existing elements
214  Coefficient(problem_->stateDim(), problem_->inputDim(), problem_->ineqDim()));
215  }
216  coeff_list_.emplace_back(problem_->stateDim());
217  for(auto & coeff : coeff_list_)
218  {
219  coeff.print_level = config_.print_level;
220  }
221 
222  // Clear trace_data_list_
223  trace_data_list_.clear();
224 
225  // Setup computation_duration_
227 
228  auto setup_time = std::chrono::system_clock::now();
229  computation_duration_.setup = calcDuration(start_time, setup_time);
230 
231  // Optimization loop
232  Status status = Status::Uninitialized;
233  for(int iter = 1; iter <= config_.max_iter; iter++)
234  {
235  status = procOnce(iter);
236  if(status != Status::IterationContinued)
237  {
238  break;
239  }
240  }
241  if(status == Status::IterationContinued)
242  {
244  }
245 
246  auto end_time = std::chrono::system_clock::now();
247  computation_duration_.opt = calcDuration(setup_time, end_time);
248  computation_duration_.solve = calcDuration(start_time, end_time);
249 
250  if(config_.print_level >= 3)
251  {
252  std::cout << "[FMPC] Solve finised. status: " << static_cast<int>(status)
253  << ", iter: " << trace_data_list_.back().iter << std::endl;
254  }
255 
256  return status;
257 }
258 
259 template<int StateDim, int InputDim, int IneqDim>
260 void FmpcSolver<StateDim, InputDim, IneqDim>::dumpTraceDataList(const std::string & file_path) const
261 {
262  std::ofstream ofs(file_path);
263  // clang-format off
264  ofs << "iter "
265  << "kkt_error "
266  << "duration_coeff "
267  << "duration_backward "
268  << "duration_forward "
269  << "duration_update" << std::endl;
270  // clang-format on
271  for(const auto & trace_data : trace_data_list_)
272  {
273  // clang-format off
274  ofs << trace_data.iter << " "
275  << trace_data.kkt_error << " "
276  << trace_data.duration_coeff << " "
277  << trace_data.duration_backward << " "
278  << trace_data.duration_forward << " "
279  << trace_data.duration_update
280  << std::endl;
281  // clang-format on
282  }
283 }
284 template<int StateDim, int InputDim, int IneqDim>
286 {
287  // Check sequence length
288  if(static_cast<int>(variable_.x_list.size()) != config_.horizon_steps + 1)
289  {
290  throw std::invalid_argument("[FMPC] x_list length should be " + std::to_string(config_.horizon_steps + 1) + " but "
291  + std::to_string(variable_.x_list.size()) + ".");
292  }
293  if(static_cast<int>(variable_.u_list.size()) != config_.horizon_steps)
294  {
295  throw std::invalid_argument("[FMPC] u_list length should be " + std::to_string(config_.horizon_steps) + " but "
296  + std::to_string(variable_.u_list.size()) + ".");
297  }
298  if(static_cast<int>(variable_.lambda_list.size()) != config_.horizon_steps + 1)
299  {
300  throw std::invalid_argument("[FMPC] lambda_list length should be " + std::to_string(config_.horizon_steps + 1)
301  + " but " + std::to_string(variable_.lambda_list.size()) + ".");
302  }
303  if(static_cast<int>(variable_.s_list.size()) != config_.horizon_steps)
304  {
305  throw std::invalid_argument("[FMPC] s_list length should be " + std::to_string(config_.horizon_steps) + " but "
306  + std::to_string(variable_.s_list.size()) + ".");
307  }
308  if(static_cast<int>(variable_.nu_list.size()) != config_.horizon_steps)
309  {
310  throw std::invalid_argument("[FMPC] nu_list length should be " + std::to_string(config_.horizon_steps) + " but "
311  + std::to_string(variable_.nu_list.size()) + ".");
312  }
313 
314  // Check element dimension
315  for(int i = 0; i < config_.horizon_steps; i++)
316  {
317  if constexpr(InputDim == Eigen::Dynamic)
318  {
319  double t = current_t_ + i * problem_->dt();
320  int input_dim = problem_->inputDim(t);
321  if(variable_.u_list[i].size() != input_dim)
322  {
323  throw std::runtime_error("[FMPC] u_list[i] dimension should be " + std::to_string(input_dim) + " but "
324  + std::to_string(variable_.u_list[i].size()) + ". i: " + std::to_string(i)
325  + ", time: " + std::to_string(t));
326  }
327  }
328  if constexpr(IneqDim == Eigen::Dynamic)
329  {
330  double t = current_t_ + i * problem_->dt();
331  int ineq_dim = problem_->ineqDim(t);
332  if(variable_.s_list[i].size() != ineq_dim)
333  {
334  throw std::runtime_error("[FMPC] s_list[i] dimension should be " + std::to_string(ineq_dim) + " but "
335  + std::to_string(variable_.s_list[i].size()) + ". i: " + std::to_string(i)
336  + ", time: " + std::to_string(t));
337  }
338  if(variable_.nu_list[i].size() != ineq_dim)
339  {
340  throw std::runtime_error("[FMPC] nu_list[i] dimension should be " + std::to_string(ineq_dim) + " but "
341  + std::to_string(variable_.nu_list[i].size()) + ". i: " + std::to_string(i)
342  + ", time: " + std::to_string(t));
343  }
344  }
345  }
346 
347  // Check non-negative
348  for(int i = 0; i < config_.horizon_steps; i++)
349  {
350  double t = current_t_ + i * problem_->dt();
351  if((variable_.s_list[i].array() < 0).any())
352  {
353  throw std::runtime_error("[FMPC] s_list[i] must be non-negative. i: " + std::to_string(i)
354  + ", time: " + std::to_string(t));
355  }
356  if((variable_.nu_list[i].array() < 0).any())
357  {
358  throw std::runtime_error("[FMPC] nu_list[i] must be non-negative. i: " + std::to_string(i)
359  + ", time: " + std::to_string(t));
360  }
361  }
362 }
363 
364 template<int StateDim, int InputDim, int IneqDim>
366 {
367  if(config_.print_level >= 3)
368  {
369  std::cout << "[FMPC] Start iteration " << iter << std::endl;
370  }
371 
372  // Append trace data
373  trace_data_list_.emplace_back();
374  auto & trace_data = trace_data_list_.back();
375  trace_data.iter = iter;
376 
377  // Update barrier parameter
379  {
380  // (19.19) in "Nocedal, Wright. Numerical optimization"
381  double s_nu_ave = 0.0;
382  double s_nu_min = std::numeric_limits<double>::max();
383  int total_ineq_dim = 0;
384  for(int i = 0; i < config_.horizon_steps; i++)
385  {
386  s_nu_ave += variable_.s_list[i].dot(variable_.nu_list[i]);
387  s_nu_min = std::min(s_nu_min, variable_.s_list[i].cwiseProduct(variable_.nu_list[i]).minCoeff());
388  total_ineq_dim += static_cast<int>(variable_.s_list[i].size());
389  }
390  s_nu_ave /= total_ineq_dim;
391 
392  double sigma = 0.5;
393  // The following equations follow (19.20) in "Nocedal, Wright. Numerical optimization" but does not work
394  // double xi = s_nu_min / s_nu_ave;
395  // double sigma = 0.1 * std::pow(std::min(0.05 * (1.0 - xi) / xi, 2.0), 3);
396  constexpr double barrier_eps_min = 1e-8;
397  constexpr double barrier_eps_max = 1e6;
398  barrier_eps_ = std::clamp(sigma * s_nu_ave, barrier_eps_min, barrier_eps_max);
399  }
400 
401  // Step 1: calculate coefficients of linearized KKT condition
402  {
403  auto start_time = std::chrono::system_clock::now();
404 
405  double dt = problem_->dt();
406  for(int i = 0; i < config_.horizon_steps; i++)
407  {
408  auto & coeff = coeff_list_[i];
409  double t = current_t_ + i * dt;
410  const StateDimVector & x = variable_.x_list[i];
411  const StateDimVector & next_x = variable_.x_list[i + 1];
412  const InputDimVector & u = variable_.u_list[i];
413  const StateDimVector & lambda = variable_.lambda_list[i];
414  const StateDimVector & next_lambda = variable_.lambda_list[i + 1];
415  const IneqDimVector & s = variable_.s_list[i];
416  const IneqDimVector & nu = variable_.nu_list[i];
417 
418  problem_->calcStateEqDeriv(t, x, u, coeff.A, coeff.B);
419  problem_->calcIneqConstDeriv(t, x, u, coeff.C, coeff.D);
420  problem_->calcRunningCostDeriv(t, x, u, coeff.Lx, coeff.Lu, coeff.Lxx, coeff.Luu, coeff.Lxu);
421 
422  coeff.x_bar = problem_->stateEq(t, x, u) - next_x; // (2.23c)
423  coeff.g_bar = problem_->ineqConst(t, x, u) + s; // (2.23d)
424  coeff.Lx_bar =
425  -1 * lambda + dt * coeff.Lx + coeff.A.transpose() * next_lambda + coeff.C.transpose() * nu; // (2.25b)
426  coeff.Lu_bar = dt * coeff.Lu + coeff.B.transpose() * next_lambda + coeff.D.transpose() * nu; // (2.25c)
427  }
428  {
429  auto & terminal_coeff = coeff_list_[config_.horizon_steps];
430  double terminal_t = current_t_ + config_.horizon_steps * dt;
431  const StateDimVector & terminal_x = variable_.x_list[config_.horizon_steps];
432  const StateDimVector & terminal_lambda = variable_.lambda_list[config_.horizon_steps];
433  problem_->calcTerminalCostDeriv(terminal_t, terminal_x, terminal_coeff.Lx, terminal_coeff.Lxx);
434  terminal_coeff.Lx_bar = terminal_coeff.Lx - terminal_lambda; // (2.25a)
435  }
436 
437  double duration = calcDuration(start_time, std::chrono::system_clock::now());
438  trace_data.duration_coeff = duration;
439  computation_duration_.coeff += duration;
440  }
441 
442  // Check KKT error
443  double kkt_error = calcKktError(0.0);
444  trace_data.kkt_error = kkt_error;
445  if(kkt_error <= config_.kkt_error_thre)
446  {
447  return Status::Succeeded;
448  }
449 
450  // Step 2: backward pass
451  {
452  auto start_time = std::chrono::system_clock::now();
453 
454  if(!backwardPass())
455  {
457  }
458 
459  double duration = calcDuration(start_time, std::chrono::system_clock::now());
460  trace_data.duration_backward = duration;
461  computation_duration_.backward += duration;
462  }
463 
464  // Step 3: forward pass
465  {
466  auto start_time = std::chrono::system_clock::now();
467 
468  if(!forwardPass())
469  {
470  return Status::ErrorInForward;
471  }
472 
473  double duration = calcDuration(start_time, std::chrono::system_clock::now());
474  trace_data.duration_forward = duration;
475  computation_duration_.forward += duration;
476  }
477 
478  // Step 4: update variables
479  {
480  auto start_time = std::chrono::system_clock::now();
481 
482  if(!updateVariables())
483  {
484  return Status::ErrorInUpdate;
485  }
486 
487  double duration = calcDuration(start_time, std::chrono::system_clock::now());
488  trace_data.duration_update = duration;
489  computation_duration_.update += duration;
490  }
491 
493 }
494 
495 template<int StateDim, int InputDim, int IneqDim>
497 {
498  double kkt_error = 0;
499 
500  {
501  kkt_error += (current_x_ - variable_.x_list[0]).squaredNorm();
502  }
503  for(int i = 0; i < config_.horizon_steps; i++)
504  {
505  const auto & coeff = coeff_list_[i];
506  kkt_error += coeff.x_bar.squaredNorm();
507  kkt_error += coeff.g_bar.squaredNorm();
508  kkt_error += coeff.Lx_bar.squaredNorm();
509  kkt_error += coeff.Lu_bar.squaredNorm();
510  kkt_error +=
511  (variable_.s_list[i].array() * variable_.nu_list[i].array() - barrier_eps).max(0).matrix().squaredNorm();
512  }
513  {
514  const auto & terminal_coeff = coeff_list_[config_.horizon_steps];
515  kkt_error += terminal_coeff.Lx_bar.squaredNorm();
516  }
517 
518  kkt_error = std::sqrt(kkt_error);
519 
520  return kkt_error;
521 }
522 
523 template<int StateDim, int InputDim, int IneqDim>
525 {
526  // To avoid repetitive memory allocation, the vector and matrix variables are created outside of loop
527  StateStateDimMatrix Qxx_tilde;
528  InputInputDimMatrix Quu_tilde;
529  StateInputDimMatrix Qxu_tilde;
530  StateDimVector Lx_tilde;
531  InputDimVector Lu_tilde;
532 
536 
537  InputDimVector k;
539  StateDimVector s;
541  StateStateDimMatrix P_symmetric;
542 
543  {
544  auto & terminal_coeff = coeff_list_[config_.horizon_steps];
545  s = -1 * terminal_coeff.Lx_bar; // (2.34)
546  P = terminal_coeff.Lxx; // (2.34)
547  terminal_coeff.s = s;
548  terminal_coeff.P = P;
549  }
550 
551  for(int i = config_.horizon_steps - 1; i >= 0; i--)
552  {
553  // Get coefficients
554  double dt = problem_->dt();
555  auto & coeff = coeff_list_[i];
556  const StateStateDimMatrix & A = coeff.A;
557  const StateInputDimMatrix & B = coeff.B;
558  const IneqStateDimMatrix & C = coeff.C;
559  const IneqInputDimMatrix & D = coeff.D;
560  const StateStateDimMatrix & Lxx = coeff.Lxx;
561  const InputInputDimMatrix & Luu = coeff.Luu;
562  const StateInputDimMatrix & Lxu = coeff.Lxu;
563  const StateDimVector & x_bar = coeff.x_bar;
564  const IneqDimVector & g_bar = coeff.g_bar;
565  const StateDimVector & Lx_bar = coeff.Lx_bar;
566  const InputDimVector & Lu_bar = coeff.Lu_bar;
567 
568  // Pre-process for gain calculation
569  {
570  auto start_time_gain_pre = std::chrono::system_clock::now();
571 
572  IneqDimVector nu_s = (variable_.nu_list[i].array() / variable_.s_list[i].array()).matrix();
573  IneqDimVector tilde_sub =
574  nu_s.cwiseProduct(g_bar) - variable_.nu_list[i] + barrier_eps_ * variable_.s_list[i].cwiseInverse();
575  Qxx_tilde.noalias() = dt * Lxx + C.transpose() * nu_s.asDiagonal() * C; // (2.28c)
576  Quu_tilde.noalias() = dt * Luu + D.transpose() * nu_s.asDiagonal() * D; // (2.28e)
577  Qxu_tilde.noalias() = dt * Lxu + C.transpose() * nu_s.asDiagonal() * D; // (2.28d)
578  Lx_tilde.noalias() = Lx_bar + C.transpose() * tilde_sub; // (2.28f)
579  Lu_tilde.noalias() = Lu_bar + D.transpose() * tilde_sub; // (2.28g)
580 
581  F.noalias() = Qxx_tilde + A.transpose() * P * A; // (2.35b)
582  H.noalias() = Qxu_tilde + A.transpose() * P * B; // (2.35c)
583  G.noalias() = Quu_tilde + B.transpose() * P * B; // (2.35d)
584 
585  computation_duration_.gain_pre += calcDuration(start_time_gain_pre, std::chrono::system_clock::now());
586  }
587 
588  // Solve linear equation for gain calculation
589  {
590  auto start_time_gain_solve = std::chrono::system_clock::now();
591 
592  int input_dim = static_cast<int>(B.cols());
593  if(input_dim > 0)
594  {
595  // In numerically difficult cases, LLT may diverge and LDLT may work.
596  Eigen::LDLT<InputInputDimMatrix> llt_G(G);
597  if(llt_G.info() == Eigen::Success)
598  {
599  k.noalias() = -1 * llt_G.solve(B.transpose() * (P * x_bar - s) + Lu_tilde); // (2.35e)
600  K.noalias() = -1 * llt_G.solve(H.transpose()); // (2.35e)
601  }
602  else
603  {
604  if(config_.print_level >= 1)
605  {
606  std::cout << "[FMPC/Backward] G is not positive definite in Cholesky decomposition (LLT)." << std::endl;
607  }
609  {
610  return false;
611  }
612  else
613  {
614  Eigen::FullPivLU<InputInputDimMatrix> lu_G(G);
615  k.noalias() = -1 * lu_G.solve(B.transpose() * (P * x_bar - s) + Lu_tilde); // (2.35e)
616  K.noalias() = -1 * lu_G.solve(H.transpose()); // (2.35e)
617  }
618  }
619  }
620  else
621  {
622  k.setZero(0);
623  K.setZero(0, problem_->stateDim());
624  }
625 
626  computation_duration_.gain_solve += calcDuration(start_time_gain_solve, std::chrono::system_clock::now());
627  }
628 
629  // Post-process for gain calculation
630  {
631  auto start_time_gain_post = std::chrono::system_clock::now();
632 
633  s = A.transpose() * (s - P * x_bar) - Lx_tilde - H * k; // (2.35a)
634  P.noalias() = F - K.transpose() * G * K; // (2.35a)
635  P_symmetric = 0.5 * (P + P.transpose()); // Enforce symmetric
636  // Assigning directly to P without using the intermediate variable P_symmetric yields incorrect results!
637  P = P_symmetric;
638 
639  computation_duration_.gain_post += calcDuration(start_time_gain_post, std::chrono::system_clock::now());
640  }
641 
642  // Save gains
643  coeff.k = k;
644  coeff.K = K;
645  coeff.s = s;
646  coeff.P = P;
647  }
648 
649  if(config_.check_nan)
650  {
651  for(const auto & coeff : coeff_list_)
652  {
653  if(coeff.containsNaN())
654  {
655  if(config_.print_level >= 1)
656  {
657  std::cout << "[FMPC/Backward] coeff contains NaN." << std::endl;
658  }
659  return false;
660  }
661  }
662  }
663 
664  return true;
665 }
666 
667 template<int StateDim, int InputDim, int IneqDim>
669 {
671 
672  for(int i = 0; i < config_.horizon_steps + 1; i++)
673  {
674  const auto & coeff = coeff_list_[i];
675 
676  delta_variable_.lambda_list[i].noalias() = coeff.P * delta_variable_.x_list[i] - coeff.s; // (2.33)
677 
678  if(i < config_.horizon_steps)
679  {
680  delta_variable_.u_list[i].noalias() = coeff.K * delta_variable_.x_list[i] + coeff.k; // (2.36)
681  delta_variable_.x_list[i + 1].noalias() =
682  coeff.A * delta_variable_.x_list[i] + coeff.B * delta_variable_.u_list[i] + coeff.x_bar; // (2.26b)
683  }
684  }
685 
686  for(int i = 0; i < config_.horizon_steps; i++)
687  {
688  const auto & coeff = coeff_list_[i];
689 
690  delta_variable_.s_list[i].noalias() =
691  -1 * (coeff.C * delta_variable_.x_list[i] + coeff.D * delta_variable_.u_list[i] + coeff.g_bar); // (2.27a)
692  delta_variable_.nu_list[i].noalias() =
693  (-1 * (variable_.nu_list[i].array() * (delta_variable_.s_list[i] + variable_.s_list[i]).array() - barrier_eps_)
694  / variable_.s_list[i].array())
695  .matrix(); // (2.27b)
696  }
697 
699  {
700  if(config_.print_level >= 1)
701  {
702  std::cout << "[FMPC/Forward] delta_variable contains NaN." << std::endl;
703  }
704  return false;
705  }
706 
707  return true;
708 }
709 
710 template<int StateDim, int InputDim, int IneqDim>
712 {
713  // Fraction-to-boundary rule
714  double alpha_s_max = 1.0;
715  double alpha_nu_max = 1.0;
716  {
717  auto start_time_fraction = std::chrono::system_clock::now();
718 
719  constexpr double margin_ratio = 0.995;
720  for(int i = 0; i < config_.horizon_steps; i++)
721  {
722  const IneqDimVector & s = variable_.s_list[i];
723  const IneqDimVector & nu = variable_.nu_list[i];
724  const IneqDimVector & delta_s = delta_variable_.s_list[i];
725  const IneqDimVector & delta_nu = delta_variable_.nu_list[i];
726  for(int ineq_idx = 0; ineq_idx < s.size(); ineq_idx++)
727  {
728  // (19.9) in "Nocedal, Wright. Numerical optimization"
729  if(delta_s[ineq_idx] < 0)
730  {
731  alpha_s_max = std::min(alpha_s_max, -1 * margin_ratio * s[ineq_idx] / delta_s[ineq_idx]);
732  }
733  if(delta_nu[ineq_idx] < 0)
734  {
735  alpha_nu_max = std::min(alpha_nu_max, -1 * margin_ratio * nu[ineq_idx] / delta_nu[ineq_idx]);
736  }
737  }
738  }
739  if(!(alpha_s_max > 0.0 && alpha_s_max <= 1.0 && alpha_nu_max > 0.0 && alpha_nu_max <= 1.0))
740  {
741  if(config_.print_level >= 1)
742  {
743  std::cout << "[FMPC/Update] Invalid alpha. barrier_eps: " << barrier_eps_ << ", alpha_s_max: " << alpha_s_max
744  << ", alpha_nu_max: " << alpha_nu_max << std::endl;
745  }
746  return false;
747  }
748 
749  computation_duration_.fraction += calcDuration(start_time_fraction, std::chrono::system_clock::now());
750  }
751 
752  // Line search
753  double alpha_s = alpha_s_max;
754  double alpha_nu = alpha_nu_max;
756  {
757  setupMeritFunc();
758 
759  constexpr double armijo_scale = 1e-3;
760  constexpr double alpha_s_update_ratio = 0.5;
761  constexpr double alpha_s_min = 1e-10;
762  Variable ls_variable = variable_;
763  while(true)
764  {
765  if(alpha_s < alpha_s_min)
766  {
767  if(config_.print_level >= 1)
768  {
769  std::cout << "[FMPC/Update] alpha_s is too small in line search backtracking. alpha_s_max: " << alpha_s_max
770  << ", alpha_s: " << alpha_s << std::endl;
771  }
772  break;
773  }
774 
775  for(int i = 0; i < config_.horizon_steps + 1; i++)
776  {
777  ls_variable.x_list[i] = variable_.x_list[i] + alpha_s * delta_variable_.x_list[i];
778 
779  if(i < config_.horizon_steps)
780  {
781  ls_variable.u_list[i] = variable_.u_list[i] + alpha_s * delta_variable_.u_list[i];
782  ls_variable.s_list[i] = variable_.s_list[i] + alpha_s * delta_variable_.s_list[i];
783  }
784  }
785 
786  double merit_func_new = calcMeritFunc(ls_variable);
787  if(merit_func_new < merit_func_ + armijo_scale * alpha_s * merit_deriv_)
788  {
789  break;
790  }
791  alpha_s *= alpha_s_update_ratio;
792  }
793  }
794 
795  if(config_.print_level >= 3)
796  {
797  std::cout << "[FMPC/update] barrier_eps: " << barrier_eps_ << ", alpha_s_max: " << alpha_s_max
798  << ", alpha_nu_max: " << alpha_nu_max << ", alpha_s: " << alpha_s << ", alpha_nu: " << alpha_nu
799  << std::endl;
800  }
801 
802  for(int i = 0; i < config_.horizon_steps + 1; i++)
803  {
804  variable_.x_list[i] += alpha_s * delta_variable_.x_list[i];
805  variable_.lambda_list[i] += alpha_nu * delta_variable_.lambda_list[i];
806 
807  if(i < config_.horizon_steps)
808  {
809  variable_.u_list[i] += alpha_s * delta_variable_.u_list[i];
810  variable_.s_list[i] += alpha_s * delta_variable_.s_list[i];
811  variable_.nu_list[i] += alpha_nu * delta_variable_.nu_list[i];
812 
813  constexpr double min_positive_value = std::numeric_limits<double>::lowest();
814  if((variable_.s_list[i].array() < 0).any())
815  {
816  if(config_.print_level >= 1)
817  {
818  std::cout << "[FMPC/Update] Updated s is negative: " << variable_.s_list[i].transpose() << std::endl;
819  }
820  variable_.s_list[i] = variable_.s_list[i].array().max(min_positive_value).matrix();
821  }
822  if((variable_.nu_list[i].array() < 0).any())
823  {
824  if(config_.print_level >= 1)
825  {
826  std::cout << "[FMPC/Update] Updated nu is negative: " << variable_.nu_list[i].transpose() << std::endl;
827  }
828  variable_.nu_list[i] = variable_.nu_list[i].array().max(min_positive_value).matrix();
829  }
830  }
831  }
832 
833  return true;
834 }
835 
836 template<int StateDim, int InputDim, int IneqDim>
838 {
839  double merit_func_obj = 0.0;
840  double merit_func_const = 0.0;
841  double merit_deriv_obj = 0.0;
842  double merit_deriv_const = 0.0;
843  double dt = problem_->dt();
844 
845  {
846  StateDimVector const_func = current_x_ - variable_.x_list[0];
847  merit_func_const += const_func.template lpNorm<1>();
848  merit_deriv_const +=
849  l1NormDirectionalDeriv(const_func, (-1 * StateStateDimMatrix::Identity()).eval(), delta_variable_.x_list[0]);
850  }
851 
852  for(int i = 0; i < config_.horizon_steps; i++)
853  {
854  double t = current_t_ + i * dt;
855  const StateDimVector & x = variable_.x_list[i];
856  const InputDimVector & u = variable_.u_list[i];
857  const IneqDimVector & s = variable_.s_list[i];
858  const StateDimVector & next_x = variable_.x_list[i + 1];
859  const StateDimVector & delta_x = delta_variable_.x_list[i];
860  const InputDimVector & delta_u = delta_variable_.u_list[i];
861  const IneqDimVector & delta_s = delta_variable_.s_list[i];
862  const StateDimVector & delta_next_x = delta_variable_.x_list[i + 1];
863  const auto & coeff = coeff_list_[i];
864 
865  {
866  merit_func_obj += problem_->runningCost(t, x, u) * dt;
867  merit_deriv_obj += (coeff.Lx.dot(delta_x) + coeff.Lu.dot(delta_u)) * dt;
868  }
869 
870  {
871  merit_func_obj += -1 * barrier_eps_ * s.array().log().sum();
872  merit_deriv_obj += -1 * barrier_eps_ * s.cwiseInverse().dot(delta_s);
873  }
874 
875  {
876  StateDimVector const_func = problem_->stateEq(t, x, u) - next_x;
877  merit_func_const += const_func.template lpNorm<1>();
878  merit_deriv_const += l1NormDirectionalDeriv(const_func, coeff.A, delta_x);
879  merit_deriv_const += l1NormDirectionalDeriv(const_func, coeff.B, delta_u);
880  merit_deriv_const +=
881  l1NormDirectionalDeriv(const_func, (-1 * StateStateDimMatrix::Identity()).eval(), delta_next_x);
882  }
883 
884  {
885  IneqDimVector const_func = problem_->ineqConst(t, x, u) + s;
886  merit_func_const += const_func.template lpNorm<1>();
887  merit_deriv_const += l1NormDirectionalDeriv(const_func, coeff.C, delta_x);
888  merit_deriv_const += l1NormDirectionalDeriv(const_func, coeff.D, delta_u);
889  merit_deriv_const += l1NormDirectionalDeriv(const_func, IneqIneqDimMatrix::Identity().eval(), delta_s);
890  }
891  }
892 
893  {
894  double terminal_t = current_t_ + config_.horizon_steps * dt;
895  const StateDimVector & terminal_x = variable_.x_list[config_.horizon_steps];
896  const StateDimVector & terminal_delta_x = delta_variable_.x_list[config_.horizon_steps];
897  const auto & terminal_coeff = coeff_list_[config_.horizon_steps];
898 
899  merit_func_obj += problem_->terminalCost(terminal_t, terminal_x);
900  merit_deriv_obj += terminal_coeff.Lx.dot(terminal_delta_x);
901  }
902 
903  constexpr double merit_const_scale_min = 1e-3;
905  {
906  // (18.32) in "Nocedal, Wright. Numerical optimization"
907  merit_const_scale_ = merit_const_scale_min;
908  for(int i = 0; i < config_.horizon_steps + 1; i++)
909  {
910  merit_const_scale_ = std::max(merit_const_scale_, variable_.lambda_list[i].cwiseAbs().maxCoeff());
911 
912  if(i < config_.horizon_steps)
913  {
914  merit_const_scale_ = std::max(merit_const_scale_, variable_.nu_list[i].cwiseAbs().maxCoeff());
915  }
916  }
917  }
918  else
919  {
920  // (18.33) in "Nocedal, Wright. Numerical optimization"
921  constexpr double rho = 0.5;
922  merit_const_scale_ = std::max(merit_deriv_obj / ((1.0 - rho) * merit_func_const), merit_const_scale_min);
923  }
924 
925  merit_func_ = merit_func_obj + merit_const_scale_ * merit_func_const;
926  merit_deriv_ = merit_deriv_obj + merit_const_scale_ * merit_deriv_const;
927 
928  if(config_.print_level >= 3)
929  {
930  std::cout << "[FMPC/merit] merit_func: " << merit_func_ << ", merit_deriv: " << merit_deriv_
931  << ", merit_const_scale: " << merit_const_scale_ << std::endl;
932  }
933 }
934 
935 template<int StateDim, int InputDim, int IneqDim>
937 {
938  double merit_func_obj = 0.0;
939  double merit_func_const = 0.0;
940  double dt = problem_->dt();
941 
942  {
943  StateDimVector const_func = current_x_ - variable.x_list[0];
944  merit_func_const += const_func.template lpNorm<1>();
945  }
946 
947  for(int i = 0; i < config_.horizon_steps; i++)
948  {
949  double t = current_t_ + i * dt;
950  const StateDimVector & x = variable.x_list[i];
951  const InputDimVector & u = variable.u_list[i];
952  const IneqDimVector & s = variable.s_list[i];
953  const StateDimVector & next_x = variable.x_list[i + 1];
954 
955  {
956  merit_func_obj += problem_->runningCost(t, x, u) * dt;
957  }
958 
959  {
960  merit_func_obj += -1 * barrier_eps_ * s.array().log().sum();
961  }
962 
963  {
964  StateDimVector const_func = problem_->stateEq(t, x, u) - next_x;
965  merit_func_const += const_func.template lpNorm<1>();
966  }
967 
968  {
969  IneqDimVector const_func = problem_->ineqConst(t, x, u) + s;
970  merit_func_const += const_func.template lpNorm<1>();
971  }
972  }
973 
974  {
975  double terminal_t = current_t_ + config_.horizon_steps * dt;
976  const StateDimVector & terminal_x = variable.x_list[config_.horizon_steps];
977 
978  merit_func_obj += problem_->terminalCost(terminal_t, terminal_x);
979  }
980 
981  return merit_func_obj + merit_const_scale_ * merit_func_const;
982 }
983 } // namespace nmpc_fmpc
984 
985 #undef CHECK_NAN
nmpc_fmpc::FmpcSolver::ComputationDuration::gain_pre
double gain_pre
Duration of pre-process for gain calculation (included in backward) [msec].
Definition: FmpcSolver.h:278
nmpc_fmpc::FmpcSolver::barrier_eps_
double barrier_eps_
Barrier parameter.
Definition: FmpcSolver.h:414
nmpc_fmpc::FmpcSolver::forwardPass
bool forwardPass()
Process forward pass a.k.a forward Riccati recursion.
Definition: FmpcSolver.hpp:668
nmpc_fmpc::FmpcSolver::solve
Status solve(double current_t, const StateDimVector &current_x, const Variable &initial_variable)
Solve optimization.
Definition: FmpcSolver.hpp:158
nmpc_fmpc::FmpcSolver::coeff_list_
std::vector< Coefficient > coeff_list_
Sequence of coefficients of linearized KKT condition.
Definition: FmpcSolver.h:399
nmpc_fmpc::FmpcSolver::Status::ErrorInUpdate
@ ErrorInUpdate
Error in update.
nmpc_fmpc::FmpcSolver::Configuration::check_nan
bool check_nan
Whether to check NaN.
Definition: FmpcSolver.h:73
nmpc_fmpc::FmpcSolver::Coefficient::containsNaN
bool containsNaN() const
Check whether NaN or infinity is containd.
Definition: FmpcSolver.hpp:134
MathUtils.h
nmpc_fmpc::l1NormDirectionalDeriv
double l1NormDirectionalDeriv(const Eigen::Matrix< double, OutputDim, 1 > &func, const Eigen::Matrix< double, OutputDim, InputDim > &jac, const Eigen::Matrix< double, InputDim, 1 > &dir)
Compute the directional derivative of the L1-norm of the function.
Definition: MathUtils.h:17
CHECK_NAN
#define CHECK_NAN(VAR, PRINT_PREFIX)
Definition: FmpcSolver.hpp:10
nmpc_fmpc::FmpcSolver::ComputationDuration::gain_post
double gain_post
Duration of post-process for gain calculation (included in backward) [msec].
Definition: FmpcSolver.h:284
nmpc_fmpc::FmpcSolver::Configuration::init_complementary_variable
bool init_complementary_variable
Whether to initialize complementarity variables.
Definition: FmpcSolver.h:76
nmpc_fmpc::FmpcSolver::Variable::nu_list
std::vector< IneqDimVector > nu_list
Sequence of Lagrange multipliers of inequality constraints (nu[0], ..., nu[N-1])
Definition: FmpcSolver.h:154
nmpc_fmpc::FmpcSolver::Variable::s_list
std::vector< IneqDimVector > s_list
Sequence of slack variables of inequality constraints (s[0], ..., s[N-1])
Definition: FmpcSolver.h:151
nmpc_fmpc::FmpcSolver::Status::Uninitialized
@ Uninitialized
Uninitialized.
nmpc_fmpc::FmpcSolver::ComputationDuration::backward
double backward
Duration to process backward pass (included in opt) [msec].
Definition: FmpcSolver.h:269
nmpc_fmpc::FmpcSolver::ComputationDuration
Data of computation duration.
Definition: FmpcSolver.h:254
nmpc_fmpc::FmpcSolver::variable
const Variable & variable() const
Const accessor to optimization variables.
Definition: FmpcSolver.h:319
nmpc_fmpc::FmpcSolver::computation_duration_
ComputationDuration computation_duration_
Computation duration data.
Definition: FmpcSolver.h:405
nmpc_fmpc::FmpcSolver::setupMeritFunc
void setupMeritFunc()
Setup the merit function and its directional derivative.
Definition: FmpcSolver.hpp:837
nmpc_fmpc::FmpcSolver::Variable::horizon_steps
int horizon_steps
Number of steps in horizon.
Definition: FmpcSolver.h:139
nmpc_fmpc::FmpcSolver::IneqStateDimMatrix
typename FmpcProblem< StateDim, InputDim, IneqDim >::IneqStateDimMatrix IneqStateDimMatrix
Type of matrix of inequality x state dimension.
Definition: FmpcSolver.h:48
nmpc_fmpc::FmpcSolver::current_x_
StateDimVector current_x_
Current state.
Definition: FmpcSolver.h:411
nmpc_fmpc::FmpcSolver::delta_variable_
Variable delta_variable_
Update amount of optimization variables.
Definition: FmpcSolver.h:396
nmpc_fmpc::FmpcSolver::Variable::lambda_list
std::vector< StateDimVector > lambda_list
Sequence of Lagrange multipliers of equality constraints (lambda[0], ..., lambda[N-1],...
Definition: FmpcSolver.h:148
nmpc_fmpc::FmpcSolver::problem_
std::shared_ptr< FmpcProblem< StateDim, InputDim, IneqDim > > problem_
FMPC problem.
Definition: FmpcSolver.h:390
nmpc_fmpc::FmpcSolver::Coefficient::Coefficient
Coefficient(int state_dim, int input_dim, int ineq_dim)
Constructor.
Definition: FmpcSolver.hpp:98
nmpc_fmpc::FmpcSolver::Configuration::break_if_llt_fails
bool break_if_llt_fails
Whether to break if LLT decomposition fails.
Definition: FmpcSolver.h:82
nmpc_fmpc::FmpcSolver::Status::Succeeded
@ Succeeded
Succeeded.
nmpc_fmpc::FmpcSolver::Configuration::update_barrier_eps
bool update_barrier_eps
Whether to update barrier parameter.
Definition: FmpcSolver.h:79
nmpc_fmpc::FmpcSolver::IneqDimVector
typename FmpcProblem< StateDim, InputDim, IneqDim >::IneqDimVector IneqDimVector
Type of vector of inequality dimension.
Definition: FmpcSolver.h:33
nmpc_fmpc::FmpcSolver::Status::ErrorInForward
@ ErrorInForward
Error in forward.
nmpc_fmpc::FmpcSolver::IneqInputDimMatrix
typename FmpcProblem< StateDim, InputDim, IneqDim >::IneqInputDimMatrix IneqInputDimMatrix
Type of matrix of inequality x input dimension.
Definition: FmpcSolver.h:51
nmpc_fmpc::FmpcSolver::Status::IterationContinued
@ IterationContinued
Iteration continued (used internally only)
nmpc_fmpc::FmpcSolver::InputDimVector
typename FmpcProblem< StateDim, InputDim, IneqDim >::InputDimVector InputDimVector
Type of vector of input dimension.
Definition: FmpcSolver.h:30
nmpc_fmpc::FmpcSolver::ComputationDuration::fraction
double fraction
Duration to calculate fraction-to-boundary rule (included in update) [msec].
Definition: FmpcSolver.h:287
nmpc_fmpc::FmpcSolver::Status::ErrorInBackward
@ ErrorInBackward
Error in backward.
nmpc_fmpc::FmpcSolver::backwardPass
bool backwardPass()
Process backward pass a.k.a backward Riccati recursion.
Definition: FmpcSolver.hpp:524
nmpc_fmpc::FmpcSolver::Variable::u_list
std::vector< InputDimVector > u_list
Sequence of input (u[0], ..., u[N-1])
Definition: FmpcSolver.h:145
nmpc_fmpc::FmpcSolver::Variable::containsNaN
bool containsNaN() const
Check whether NaN or infinity is containd.
Definition: FmpcSolver.hpp:71
nmpc_fmpc::FmpcSolver::Variable::Variable
Variable(int _horizon_steps=0)
Constructor.
Definition: FmpcSolver.hpp:32
nmpc_fmpc::FmpcSolver::Variable
Optimization variables.
Definition: FmpcSolver.h:117
nmpc_fmpc::FmpcSolver::Coefficient
Coefficients of linearized KKT condition.
Definition: FmpcSolver.h:161
nmpc_fmpc::FmpcSolver::merit_func_
double merit_func_
Merit function.
Definition: FmpcSolver.h:420
nmpc_fmpc::FmpcSolver::calcMeritFunc
double calcMeritFunc(const Variable &variable) const
Calculate merit function.
Definition: FmpcSolver.hpp:936
nmpc_fmpc::FmpcSolver::variable_
Variable variable_
Optimization variables.
Definition: FmpcSolver.h:393
nmpc_fmpc::FmpcSolver::dumpTraceDataList
void dumpTraceDataList(const std::string &file_path) const
Dump trace data list.
Definition: FmpcSolver.hpp:260
nmpc_fmpc::FmpcSolver::InputInputDimMatrix
typename FmpcProblem< StateDim, InputDim, IneqDim >::InputInputDimMatrix InputInputDimMatrix
Type of matrix of input x input dimension.
Definition: FmpcSolver.h:39
nmpc_fmpc::FmpcSolver::trace_data_list_
std::vector< TraceData > trace_data_list_
Sequence of trace data.
Definition: FmpcSolver.h:402
nmpc_fmpc::FmpcSolver::Status::MaxIterationReached
@ MaxIterationReached
Maximum iteration reached.
nmpc_fmpc::FmpcSolver::ComputationDuration::update
double update
Duration to update variables (included in opt) [msec].
Definition: FmpcSolver.h:275
nmpc_fmpc::FmpcSolver::Configuration::horizon_steps
int horizon_steps
Number of steps in horizon.
Definition: FmpcSolver.h:64
nmpc_fmpc::FmpcSolver::calcKktError
double calcKktError(double barrier_eps) const
Calculate KKT condition error.
Definition: FmpcSolver.hpp:496
nmpc_fmpc::FmpcSolver::Configuration::enable_line_search
bool enable_line_search
Whether to enable line search.
Definition: FmpcSolver.h:85
nmpc_fmpc::FmpcSolver::Status
Status
Result status.
Definition: FmpcSolver.h:92
nmpc_fmpc::FmpcSolver::Configuration::print_level
int print_level
Print level (0: no print, 1: print only important, 2: print verbose, 3: print very verbose)
Definition: FmpcSolver.h:61
nmpc_fmpc::FmpcSolver::current_t_
double current_t_
Current time [sec].
Definition: FmpcSolver.h:408
nmpc_fmpc::FmpcSolver::StateStateDimMatrix
typename FmpcProblem< StateDim, InputDim, IneqDim >::StateStateDimMatrix StateStateDimMatrix
Type of matrix of state x state dimension.
Definition: FmpcSolver.h:36
nmpc_fmpc::FmpcSolver::Variable::print_level
int print_level
Print level (0: no print, 1: print only important, 2: print verbose, 3: print very verbose)
Definition: FmpcSolver.h:157
nmpc_fmpc::FmpcSolver::Variable::reset
void reset(double _x, double _u, double _lambda, double _s, double _nu)
Reset variables.
Definition: FmpcSolver.hpp:42
nmpc_fmpc::FmpcSolver::ComputationDuration::solve
double solve
Duration to solve [msec].
Definition: FmpcSolver.h:257
nmpc_fmpc::FmpcSolver::Configuration::max_iter
int max_iter
Maximum iteration of optimization loop.
Definition: FmpcSolver.h:67
nmpc_fmpc::FmpcSolver::checkVariable
void checkVariable() const
Check optimization variables.
Definition: FmpcSolver.hpp:285
nmpc_fmpc::FmpcSolver::ComputationDuration::opt
double opt
Duration of optimization loop (included in solve) [msec].
Definition: FmpcSolver.h:263
nmpc_fmpc::FmpcSolver::merit_const_scale_
double merit_const_scale_
Scale of constraint errors in the merit function.
Definition: FmpcSolver.h:417
nmpc_fmpc::FmpcSolver::StateDimVector
typename FmpcProblem< StateDim, InputDim, IneqDim >::StateDimVector StateDimVector
Type of vector of state dimension.
Definition: FmpcSolver.h:27
nmpc_fmpc::FmpcSolver::updateVariables
bool updateVariables()
Update optimization variables given Newton-step direction.
Definition: FmpcSolver.hpp:711
nmpc_fmpc::FmpcSolver::Configuration::merit_const_scale_from_lagrange_multipliers
bool merit_const_scale_from_lagrange_multipliers
Whether to calculate the scale of constraint errors in the merit function from Lagrange multipliers.
Definition: FmpcSolver.h:88
nmpc_fmpc::FmpcSolver::config_
Configuration config_
Configuration.
Definition: FmpcSolver.h:387
nmpc_fmpc
Definition: FmpcProblem.h:7
nmpc_fmpc::FmpcSolver::Variable::x_list
std::vector< StateDimVector > x_list
Sequence of state (x[0], ..., x[N-1], x[N])
Definition: FmpcSolver.h:142
nmpc_fmpc::FmpcSolver::procOnce
Status procOnce(int iter)
Process one iteration.
Definition: FmpcSolver.hpp:365
nmpc_fmpc::FmpcSolver::ComputationDuration::setup
double setup
Duration to setup (included in solve) [msec].
Definition: FmpcSolver.h:260
nmpc_fmpc::FmpcSolver::ComputationDuration::gain_solve
double gain_solve
Duration to solve linear equation for gain calculation (included in backward) [msec].
Definition: FmpcSolver.h:281
nmpc_fmpc::FmpcSolver::InputStateDimMatrix
typename FmpcProblem< StateDim, InputDim, IneqDim >::InputStateDimMatrix InputStateDimMatrix
Type of matrix of input x state dimension.
Definition: FmpcSolver.h:45
nmpc_fmpc::FmpcSolver::Configuration::kkt_error_thre
double kkt_error_thre
Threshold of KKT condition error.
Definition: FmpcSolver.h:70
nmpc_fmpc::FmpcSolver::merit_deriv_
double merit_deriv_
Directional derivative of merit function.
Definition: FmpcSolver.h:423
nmpc_fmpc::FmpcSolver::ComputationDuration::forward
double forward
Duration to process forward pass (included in opt) [msec].
Definition: FmpcSolver.h:272
nmpc_fmpc::FmpcSolver::StateInputDimMatrix
typename FmpcProblem< StateDim, InputDim, IneqDim >::StateInputDimMatrix StateInputDimMatrix
Type of matrix of state x input dimension.
Definition: FmpcSolver.h:42
nmpc_fmpc::FmpcSolver::ComputationDuration::coeff
double coeff
Duration to calculate coefficients (included in opt) [msec].
Definition: FmpcSolver.h:266