nmpc_ddp
DDPSolver.hpp
Go to the documentation of this file.
1 /* Author: Masaki Murooka */
2 
3 #include <chrono>
4 #include <fstream>
5 #include <iostream>
6 
7 #include <nmpc_ddp/BoxQP.h>
8 
9 namespace
10 {
11 template<class Clock>
12 double calcDuration(const std::chrono::time_point<Clock> & start_time, const std::chrono::time_point<Clock> & end_time)
13 {
14  return 1e3 * std::chrono::duration_cast<std::chrono::duration<double>>(end_time - start_time).count();
15 }
16 } // namespace
17 
18 namespace nmpc_ddp
19 {
20 template<int StateDim, int InputDim>
22 : problem_(problem)
23 {
24 }
25 
26 template<int StateDim, int InputDim>
28  const StateDimVector & current_x,
29  const std::vector<InputDimVector> & initial_u_list)
30 {
31  computation_duration_ = ComputationDuration();
32 
33  auto start_time = std::chrono::system_clock::now();
34 
35  // Initialize variables
36  current_t_ = current_t;
37  lambda_ = config_.initial_lambda;
38  dlambda_ = config_.initial_dlambda;
39 
40  // Check initial_u_list
41  if(static_cast<int>(initial_u_list.size()) != config_.horizon_steps)
42  {
43  throw std::invalid_argument("initial_u_list length should be " + std::to_string(config_.horizon_steps) + " but "
44  + std::to_string(initial_u_list.size()) + ".");
45  }
46  if constexpr(InputDim == Eigen::Dynamic)
47  {
48  for(int i = 0; i < config_.horizon_steps; i++)
49  {
50  double t = current_t_ + i * problem_->dt();
51  if(initial_u_list[i].size() != problem_->inputDim(t))
52  {
53  throw std::runtime_error("initial_u dimension should be " + std::to_string(problem_->inputDim(t)) + " but "
54  + std::to_string(initial_u_list[i].size()) + ". i: " + std::to_string(i)
55  + ", time: " + std::to_string(t));
56  }
57  }
58  }
59 
60  // Resize list
61  candidate_control_data_.x_list.resize(config_.horizon_steps + 1);
62  candidate_control_data_.u_list.resize(config_.horizon_steps);
63  candidate_control_data_.cost_list.resize(config_.horizon_steps + 1);
64  int outer_dim = config_.use_state_eq_second_derivative ? problem_->stateDim() : 0;
65  if constexpr(InputDim == Eigen::Dynamic)
66  {
67  derivative_list_.clear();
68  for(int i = 0; i < config_.horizon_steps; i++)
69  {
70  double t = current_t_ + i * problem_->dt();
71  derivative_list_.push_back(Derivative(problem_->stateDim(), problem_->inputDim(t), outer_dim));
72  }
73  }
74  else
75  {
76  // This assumes that the dimension is fixed, but it is efficient because it preserves existing elements
77  derivative_list_.resize(config_.horizon_steps, Derivative(problem_->stateDim(), problem_->inputDim(), outer_dim));
78  }
79  k_list_.resize(config_.horizon_steps);
80  K_list_.resize(config_.horizon_steps);
81 
82  // Initialize state and cost sequence
83  control_data_.u_list = initial_u_list;
84  if(config_.with_input_constraint)
85  {
86  // Impose input limits
87  for(int i = 0; i < config_.horizon_steps; ++i)
88  {
89  const double t = current_t_ + i * problem_->dt();
90  const auto & u_limits = input_limits_func_(t);
91  control_data_.u_list[i] = control_data_.u_list[i].cwiseMax(u_limits[0]).cwiseMin(u_limits[1]);
92  }
93  }
94  control_data_.x_list.resize(config_.horizon_steps + 1);
95  control_data_.cost_list.resize(config_.horizon_steps + 1);
96  control_data_.x_list[0] = current_x;
97  for(int i = 0; i < config_.horizon_steps; i++)
98  {
99  double t = current_t_ + i * problem_->dt();
100  control_data_.x_list[i + 1] = problem_->stateEq(t, control_data_.x_list[i], control_data_.u_list[i]);
101  control_data_.cost_list[i] = problem_->runningCost(t, control_data_.x_list[i], control_data_.u_list[i]);
102  }
103  double terminal_t = current_t_ + config_.horizon_steps * problem_->dt();
104  control_data_.cost_list[config_.horizon_steps] =
105  problem_->terminalCost(terminal_t, control_data_.x_list[config_.horizon_steps]);
106 
107  // Initialize trace data
108  trace_data_list_.clear();
109  TraceData initial_trace_data;
110  initial_trace_data.iter = 0;
111  initial_trace_data.cost = control_data_.cost_list.sum();
112  initial_trace_data.lambda = lambda_;
113  initial_trace_data.dlambda = dlambda_;
114  trace_data_list_.push_back(initial_trace_data);
115 
116  if(config_.print_level >= 3)
117  {
118  std::cout << "[DDP] Initial cost: " << control_data_.cost_list.sum() << std::endl;
119  }
120 
121  auto setup_time = std::chrono::system_clock::now();
122  computation_duration_.setup = calcDuration(start_time, setup_time);
123 
124  // Optimization loop
125  int retval = 0;
126  for(int iter = 1; iter <= config_.max_iter; iter++)
127  {
128  retval = procOnce(iter);
129  if(retval != 0)
130  {
131  break;
132  }
133  }
134 
135  if(config_.print_level >= 3)
136  {
137  std::cout << "[DDP] Final cost: " << control_data_.cost_list.sum() << std::endl;
138  }
139 
140  auto end_time = std::chrono::system_clock::now();
141  computation_duration_.opt = calcDuration(setup_time, end_time);
142  computation_duration_.solve = calcDuration(start_time, end_time);
143 
144  if(config_.print_level >= 3)
145  {
146  std::cout << "[DDP] Setup duration: " << computation_duration_.setup
147  << " [ms], optimization duration: " << computation_duration_.opt << " [ms]." << std::endl;
148  }
149 
150  return retval == 1;
151 }
152 
153 template<int StateDim, int InputDim>
155 {
156  if(config_.print_level >= 3)
157  {
158  std::cout << "[DDP] Start iteration " << iter << std::endl;
159  }
160 
161  // Append trace data
162  trace_data_list_.push_back(TraceData());
163  auto & trace_data = trace_data_list_.back();
164  trace_data.iter = iter;
165 
166  // Step 1: differentiate dynamics and cost along new trajectory
167  {
168  auto start_time = std::chrono::system_clock::now();
169 
170  for(int i = 0; i < config_.horizon_steps; i++)
171  {
172  auto & derivative = derivative_list_[i];
173 
174  double t = current_t_ + i * problem_->dt();
175  const StateDimVector & x = control_data_.x_list[i];
176  const InputDimVector & u = control_data_.u_list[i];
177  if(config_.use_state_eq_second_derivative)
178  {
179  problem_->calcStateEqDeriv(t, x, u, derivative.Fx, derivative.Fu, derivative.Fxx, derivative.Fuu,
180  derivative.Fxu);
181  }
182  else
183  {
184  problem_->calcStateEqDeriv(t, x, u, derivative.Fx, derivative.Fu);
185  }
186  problem_->calcRunningCostDeriv(t, x, u, derivative.Lx, derivative.Lu, derivative.Lxx, derivative.Luu,
187  derivative.Lxu);
188  }
189  double terminal_t = current_t_ + config_.horizon_steps * problem_->dt();
190  problem_->calcTerminalCostDeriv(terminal_t, control_data_.x_list[config_.horizon_steps], last_Vx_, last_Vxx_);
191 
192  double duration_derivative = calcDuration(start_time, std::chrono::system_clock::now());
193  trace_data.duration_derivative = duration_derivative;
194  computation_duration_.derivative += duration_derivative;
195  }
196 
197  // Step 2: backward pass, compute optimal control law and cost-to-go
198  {
199  auto start_time = std::chrono::system_clock::now();
200 
201  while(!backwardPass())
202  {
203  // Increase lambda
204  dlambda_ = std::max(dlambda_ * config_.lambda_factor, config_.lambda_factor);
205  lambda_ = std::max(lambda_ * dlambda_, config_.lambda_min);
206  if(lambda_ > config_.lambda_max)
207  {
208  if(config_.print_level >= 1)
209  {
210  std::cout << "[DDP/Backward] Failure due to large lambda. (time: " << current_t_ << ", iter: " << iter << ")"
211  << std::endl;
212  }
213  return -1; // Failure
214  }
215  if(config_.print_level >= 3)
216  {
217  std::cout << "[DDP/Backward] Increase lambda to " << lambda_ << std::endl;
218  }
219  }
220 
221  double duration_backward = calcDuration(start_time, std::chrono::system_clock::now());
222  trace_data.duration_backward = duration_backward;
223  computation_duration_.backward += duration_backward;
224  }
225 
226  // Check for termination due to small gradient
227  double k_rel_norm = 0;
228  for(int i = 0; i < config_.horizon_steps; i++)
229  {
230  k_rel_norm = std::max(k_rel_norm, k_list_[i].norm() / (control_data_.u_list[i].norm() + 1.0));
231  }
232  trace_data.k_rel_norm = k_rel_norm;
233  if(k_rel_norm < config_.k_rel_norm_thre && lambda_ < config_.lambda_thre)
234  {
235  if(config_.print_level >= 2)
236  {
237  std::cout << "[DDP] Terminate due to small gradient. (time: " << current_t_ << ", iter: " << iter << ")"
238  << std::endl;
239  }
240  return 1; // Terminate
241  }
242 
243  // Step 3: forward pass, line-search to find new control sequence, trajectory, cost
244  bool forward_pass_success = false;
245  double cost_update_actual = 0;
246  {
247  auto start_time = std::chrono::system_clock::now();
248 
249  double alpha = 0;
250  double cost_update_expected = 0;
251  double cost_update_ratio = 0;
252  for(int i = 0; i < config_.alpha_list.size(); i++)
253  {
254  alpha = config_.alpha_list[i];
255 
256  forwardPass(alpha);
257 
258  cost_update_actual = control_data_.cost_list.sum() - candidate_control_data_.cost_list.sum();
259  cost_update_expected = -1 * alpha * (dV_[0] + alpha * dV_[1]);
260 
261  constexpr double update_eps = 1e-12;
262  if(std::abs(cost_update_expected) < update_eps)
263  {
264  // The local model predicts no meaningful improvement
265  if(std::abs(cost_update_actual) < update_eps)
266  {
267  // Numerically stationary. Do not form 0 / 0.
268  cost_update_ratio = 1.0;
269  forward_pass_success = true;
270  break;
271  }
272  else
273  {
274  // Expected update is zero, but an actual cost was changed
275  // (TODO: this should be regarded as forward_pass_success=true when cost_update_actual is positive?)
276  cost_update_ratio = (cost_update_actual > 0) ? 1 : -1;
277  }
278  }
279  else
280  {
281  cost_update_ratio = cost_update_actual / cost_update_expected;
282  if(cost_update_expected < 0)
283  {
284  if((!config_.with_input_constraint && config_.print_level >= 0)
285  || (config_.with_input_constraint && config_.print_level >= 2))
286  {
287  std::cout << "[DDP/Forward] Value is not expected to decrease." << std::endl;
288  }
289  cost_update_ratio = (cost_update_actual >= 0 ? 1 : -1);
290  }
291  if(cost_update_ratio > config_.cost_update_ratio_thre)
292  {
293  forward_pass_success = true;
294  break;
295  }
296  }
297  }
298  trace_data.alpha = alpha;
299  trace_data.cost_update_actual = cost_update_actual;
300  trace_data.cost_update_expected = cost_update_expected;
301  trace_data.cost_update_ratio = cost_update_ratio;
302 
303  double duration_forward = calcDuration(start_time, std::chrono::system_clock::now());
304  trace_data.duration_forward = duration_forward;
305  computation_duration_.forward += duration_forward;
306  }
307  if(!forward_pass_success && config_.print_level >= 3)
308  {
309  std::cout << "[DDP] Forward pass failed." << std::endl;
310  }
311 
312  // Step 4: accept step (or not)
313  int retval = 0; // Continue
314  if(forward_pass_success)
315  {
316  // Accept changes
317  control_data_.x_list = candidate_control_data_.x_list;
318  control_data_.u_list = candidate_control_data_.u_list;
319  control_data_.cost_list = candidate_control_data_.cost_list;
320 
321  // Check for termination due to small cost update
322  if(cost_update_actual < config_.cost_update_thre)
323  {
324  if(config_.print_level >= 2)
325  {
326  std::cout << "[DDP] Terminate due to small cost update. (time: " << current_t_ << ", iter: " << iter << ")"
327  << std::endl;
328  }
329  retval = 1; // Terminate
330  }
331 
332  // Decrease lambda
333  dlambda_ = std::min(dlambda_ / config_.lambda_factor, 1 / config_.lambda_factor);
334  if(lambda_ >= config_.lambda_min)
335  {
336  lambda_ *= dlambda_;
337  }
338  else
339  {
340  lambda_ = 0;
341  }
342  if(config_.print_level >= 3)
343  {
344  std::cout << "[DDP/Forward] Decrease lambda to " << lambda_ << std::endl;
345  }
346  }
347  else
348  {
349  // Increase lambda
350  dlambda_ = std::max(dlambda_ * config_.lambda_factor, config_.lambda_factor);
351  lambda_ = std::max(lambda_ * dlambda_, config_.lambda_min);
352  if(lambda_ > config_.lambda_max)
353  {
354  if(config_.print_level >= 1)
355  {
356  std::cout << "[DDP/Forward] Failure due to large lambda. (time: " << current_t_ << ", iter: " << iter << ")"
357  << std::endl;
358  }
359  retval = -1; // Failure
360  }
361  if(config_.print_level >= 3)
362  {
363  std::cout << "[DDP/Forward] Increase lambda to " << lambda_ << std::endl;
364  }
365  }
366 
367  trace_data.cost = control_data_.cost_list.sum();
368  trace_data.lambda = lambda_;
369  trace_data.dlambda = dlambda_;
370 
371  return retval;
372 }
373 
374 template<int StateDim, int InputDim>
376 {
377  // To avoid repetitive memory allocation, the vector and matrix variables are created outside of loop
378  StateDimVector Vx = last_Vx_;
379  StateStateDimMatrix Vxx = last_Vxx_;
380  StateStateDimMatrix Vxx_reg;
381  StateStateDimMatrix Vxx_symmetric;
382 
383  InputDimVector Qu;
384  StateDimVector Qx;
388  InputStateDimMatrix Qux_reg;
389  InputInputDimMatrix Quu_F;
390 
391  InputStateDimMatrix VxFux;
392  InputInputDimMatrix VxFuu;
393 
394  InputDimVector k;
396 
397  dV_.setZero();
398 
399  for(int i = config_.horizon_steps - 1; i >= 0; i--)
400  {
401  // Get derivatives
402  double t = current_t_ + i * problem_->dt();
403  const StateStateDimMatrix & Fx = derivative_list_[i].Fx;
404  const StateInputDimMatrix & Fu = derivative_list_[i].Fu;
405  // const std::vector<StateStateDimMatrix> & Fxx = derivative_list_[i].Fxx;
406  // const std::vector<InputInputDimMatrix> & Fuu = derivative_list_[i].Fuu;
407  // const std::vector<StateInputDimMatrix> & Fxu = derivative_list_[i].Fxu;
408  const StateDimVector & Lx = derivative_list_[i].Lx;
409  const InputDimVector & Lu = derivative_list_[i].Lu;
410  const StateStateDimMatrix & Lxx = derivative_list_[i].Lxx;
411  const InputInputDimMatrix & Luu = derivative_list_[i].Luu;
412  const StateInputDimMatrix & Lxu = derivative_list_[i].Lxu;
413  int input_dim = static_cast<int>(Fu.cols());
414 
415  // Calculate Q
416  auto start_time_Q = std::chrono::system_clock::now();
417 
418  Qu.noalias() = Lu + Fu.transpose() * Vx;
419 
420  Qx.noalias() = Lx + Fx.transpose() * Vx;
421 
422  Qux.noalias() = Lxu.transpose() + Fu.transpose() * Vxx * Fx;
423  if(config_.use_state_eq_second_derivative)
424  {
425  throw std::runtime_error("Vector-tensor product is not implemented yet.");
426  // \todo Need operation to compute a matrix by vector and tensor product
427  // VxFux = Vx * Fxu.transpose();
428  // Qux += VxFux
429  }
430 
431  Quu.noalias() = Luu + Fu.transpose() * Vxx * Fu;
432  if(config_.use_state_eq_second_derivative)
433  {
434  throw std::runtime_error("Vector-tensor product is not implemented yet.");
435  // \todo Need operation to compute a matrix by vector and tensor product
436  // VxFuu = Vx * Fuu;
437  // Quu += VxFuu;
438  }
439 
440  Qxx.noalias() = Lxx + Fx.transpose() * Vxx * Fx;
441  if(config_.use_state_eq_second_derivative)
442  {
443  throw std::runtime_error("Vector-tensor product is not implemented yet.");
444  // \todo Need operation to compute a matrix by vector and tensor product
445  // Qxx += Vx * Fxx;
446  }
447 
448  computation_duration_.Q += calcDuration(start_time_Q, std::chrono::system_clock::now());
449 
450  // Calculate regularization
451  auto start_time_reg = std::chrono::system_clock::now();
452 
453  Vxx_reg = Vxx;
454  if(config_.reg_type == 2)
455  {
456  Vxx_reg.diagonal().array() += lambda_;
457  }
458 
459  Qux_reg.noalias() = Lxu.transpose() + Fu.transpose() * Vxx_reg * Fx;
460  if(config_.use_state_eq_second_derivative)
461  {
462  Qux_reg += VxFux;
463  }
464 
465  Quu_F.noalias() = Luu + Fu.transpose() * Vxx_reg * Fu;
466  if(config_.use_state_eq_second_derivative)
467  {
468  Quu_F += VxFuu;
469  }
470  if(config_.reg_type == 1)
471  {
472  Quu_F.diagonal().array() += lambda_;
473  }
474 
475  computation_duration_.reg += calcDuration(start_time_reg, std::chrono::system_clock::now());
476 
477  // Calculate gains
478  auto start_time_gain = std::chrono::system_clock::now();
479 
480  if(input_dim > 0)
481  {
482  if(config_.with_input_constraint)
483  {
484  InputDimVector initial_k;
485  if(i == config_.horizon_steps - 1)
486  {
487  initial_k.setZero(input_dim);
488  }
489  else
490  {
491  if(k_list_[i + 1].size() == input_dim)
492  {
493  initial_k = k_list_[i + 1];
494  }
495  else
496  {
497  initial_k.setZero(input_dim);
498  }
499  }
500 
501  BoxQP<Eigen::Dynamic> qp(static_cast<int>(Quu_F.cols()));
502  const auto & u_limits = input_limits_func_(t);
503  k = qp.solve(Quu_F, Qu, u_limits[0] - control_data_.u_list[i], u_limits[1] - control_data_.u_list[i],
504  initial_k);
505  if(qp.retval_ < 0)
506  {
507  if(config_.print_level >= 1)
508  {
509  std::cout << "[DDP/Backward] Failed BoxQP: " << qp.retstr_.at(qp.retval_) << std::endl;
510  }
511  return false;
512  }
513 
514  const auto & free_idxs = qp.free_idxs_;
515  K.setZero(input_dim, problem_->stateDim());
516  if(free_idxs.size() > 0)
517  {
518  Eigen::MatrixXd Qux_reg_free(free_idxs.size(), problem_->stateDim());
519  for(size_t j = 0; j < free_idxs.size(); j++)
520  {
521  Qux_reg_free.row(j) = Qux_reg.row(free_idxs[j]);
522  }
523  Eigen::MatrixXd K_free = -1 * qp.llt_free_->solve(Qux_reg_free);
524  for(size_t j = 0; j < free_idxs.size(); j++)
525  {
526  K.row(free_idxs[j]) = K_free.row(j);
527  }
528  }
529  }
530  else
531  {
532  Eigen::LLT<InputInputDimMatrix> llt_Quu_F(Quu_F);
533  if(llt_Quu_F.info() == Eigen::NumericalIssue)
534  {
535  if(config_.print_level >= 1)
536  {
537  std::cout << "[DDP/Backward] Quu_F is not positive definite in Cholesky decomposition (LLT)." << std::endl;
538  }
539  return false;
540  }
541  k = -1 * llt_Quu_F.solve(Qu);
542  K = -1 * llt_Quu_F.solve(Qux_reg);
543  }
544  }
545  else
546  {
547  k.setZero(0);
548  K.setZero(0, problem_->stateDim());
549  }
550 
551  computation_duration_.gain += calcDuration(start_time_gain, std::chrono::system_clock::now());
552 
553  // Update cost-to-go approximation
554  dV_ += Eigen::Vector2d(k.dot(Qu), 0.5 * k.dot(Quu * k));
555  Vx.noalias() = Qx + K.transpose() * Quu * k + K.transpose() * Qu + Qux.transpose() * k;
556  Vxx.noalias() = Qxx + K.transpose() * Quu * K + K.transpose() * Qux + Qux.transpose() * K;
557  Vxx_symmetric = 0.5 * (Vxx + Vxx.transpose());
558  Vxx = Vxx_symmetric;
559 
560  // Save gains
561  k_list_[i] = k;
562  K_list_[i] = K;
563  }
564 
565  return true;
566 }
567 
568 template<int StateDim, int InputDim>
570 {
571  // Set initial state
572  candidate_control_data_.x_list[0] = control_data_.x_list[0];
573 
574  for(int i = 0; i < config_.horizon_steps; i++)
575  {
576  // Calculate input
577  candidate_control_data_.u_list[i] = control_data_.u_list[i] + alpha * k_list_[i]
578  + K_list_[i] * (candidate_control_data_.x_list[i] - control_data_.x_list[i]);
579 
580  // Impose constraints on input
581  const double t = current_t_ + i * problem_->dt();
582  if(config_.with_input_constraint)
583  {
584  const auto & u_limits = input_limits_func_(t);
585  candidate_control_data_.u_list[i] = candidate_control_data_.u_list[i].cwiseMax(u_limits[0]).cwiseMin(u_limits[1]);
586  }
587 
588  // Calculate next state and cost
589  candidate_control_data_.x_list[i + 1] =
590  problem_->stateEq(t, candidate_control_data_.x_list[i], candidate_control_data_.u_list[i]);
591  candidate_control_data_.cost_list[i] =
592  problem_->runningCost(t, candidate_control_data_.x_list[i], candidate_control_data_.u_list[i]);
593  }
594  double terminal_t = current_t_ + config_.horizon_steps * problem_->dt();
595  candidate_control_data_.cost_list[config_.horizon_steps] =
596  problem_->terminalCost(terminal_t, candidate_control_data_.x_list[config_.horizon_steps]);
597 }
598 
599 template<int StateDim, int InputDim>
600 void DDPSolver<StateDim, InputDim>::dumpTraceDataList(const std::string & file_path) const
601 {
602  std::ofstream ofs(file_path);
603  // clang-format off
604  ofs << "iter "
605  << "cost "
606  << "lambda "
607  << "dlambda "
608  << "alpha "
609  << "k_rel_norm "
610  << "cost_update_actual "
611  << "cost_update_expected "
612  << "cost_update_ratio "
613  << "duration_derivative "
614  << "duration_backward "
615  << "duration_forward" << std::endl;
616  // clang-format on
617  for(const auto & trace_data : trace_data_list_)
618  {
619  // clang-format off
620  ofs << trace_data.iter << " "
621  << trace_data.cost << " "
622  << trace_data.lambda << " "
623  << trace_data.dlambda << " "
624  << trace_data.alpha << " "
625  << trace_data.k_rel_norm << " "
626  << trace_data.cost_update_actual << " "
627  << trace_data.cost_update_expected << " "
628  << trace_data.cost_update_ratio << " "
629  << trace_data.duration_derivative << " "
630  << trace_data.duration_backward << " "
631  << trace_data.duration_forward
632  << std::endl;
633  // clang-format on
634  }
635 }
636 } // namespace nmpc_ddp
Solver for quadratic programming problems with box constraints (i.e., only upper and lower bounds).
Definition: BoxQP.h:20
std::unique_ptr< Eigen::LLT< Eigen::MatrixXd > > llt_free_
Cholesky decomposition (LLT) of free block of objective Hessian matrix.
Definition: BoxQP.h:386
const std::unordered_map< int, std::string > retstr_
Return string.
Definition: BoxQP.h:375
std::vector< int > free_idxs_
Indices of free dimensions in decision variables.
Definition: BoxQP.h:389
int retval_
Return value.
Definition: BoxQP.h:372
VarDimVector solve(const VarVarDimMatrix &H, const VarDimVector &g, const VarDimVector &lower, const VarDimVector &upper)
Solve optimization.
Definition: BoxQP.h:126
DDP problem.
Definition: DDPProblem.h:17
typename DDPProblem< StateDim, InputDim >::StateStateDimMatrix StateStateDimMatrix
Type of matrix of state x state dimension.
Definition: DDPSolver.h:34
void forwardPass(double alpha)
Process forward pass.
Definition: DDPSolver.hpp:569
bool backwardPass()
Process backward pass.
Definition: DDPSolver.hpp:375
typename DDPProblem< StateDim, InputDim >::InputInputDimMatrix InputInputDimMatrix
Type of matrix of input x input dimension.
Definition: DDPSolver.h:37
typename DDPProblem< StateDim, InputDim >::StateInputDimMatrix StateInputDimMatrix
Type of matrix of state x input dimension.
Definition: DDPSolver.h:40
typename DDPProblem< StateDim, InputDim >::StateDimVector StateDimVector
Type of vector of state dimension.
Definition: DDPSolver.h:28
void dumpTraceDataList(const std::string &file_path) const
Dump trace data list.
Definition: DDPSolver.hpp:600
typename DDPProblem< StateDim, InputDim >::InputStateDimMatrix InputStateDimMatrix
Type of matrix of input x state dimension.
Definition: DDPSolver.h:43
int procOnce(int iter)
Process one iteration.
Definition: DDPSolver.hpp:154
typename DDPProblem< StateDim, InputDim >::InputDimVector InputDimVector
Type of vector of input dimension.
Definition: DDPSolver.h:31
bool solve(double current_t, const StateDimVector &current_x, const std::vector< InputDimVector > &initial_u_list)
Solve optimization.
Definition: DDPSolver.hpp:27
EIGEN_MAKE_ALIGNED_OPERATOR_NEW DDPSolver(const std::shared_ptr< DDPProblem< StateDim, InputDim >> &problem)
Constructor.
Definition: DDPSolver.hpp:21
Definition: BoxQP.h:10
Data of computation duration.
Definition: DDPSolver.h:220
Derivatives of DDP problem.
Definition: DDPSolver.h:127
Data to trace optimization loop.
Definition: DDPSolver.h:180
double lambda
Regularization coefficient.
Definition: DDPSolver.h:188
int iter
Iteration of optimization loop.
Definition: DDPSolver.h:182
double cost
Total cost.
Definition: DDPSolver.h:185
double dlambda
Scaling factor of regularization coefficient.
Definition: DDPSolver.h:191