38 if (pointer->type() !=
"exotica::DynamicTimeIndexedShootingProblem")
40 ThrowNamed(
"This ILQGSolver can't solve problem of type '" << pointer->type() <<
"'!");
44 prob_ = std::static_pointer_cast<DynamicTimeIndexedShootingProblem>(pointer);
51 constexpr
double min_clamp_ = -1e10;
52 constexpr
double max_clamp_ = 1e10;
53 const int T =
prob_->get_T();
55 const int NU =
prob_->GetScene()->get_num_controls();
58 Eigen::VectorXd big_C_times_little_c = Eigen::VectorXd::Zero(NU, 1);
59 Eigen::MatrixXd big_C_times_big_C = Eigen::MatrixXd::Zero(NU, NU);
60 Eigen::MatrixXd little_c_times_little_c = Eigen::MatrixXd::Zero(1, 1);
63 double s0 =
prob_->GetStateCost(T - 1);
64 Eigen::MatrixXd
s =
prob_->GetStateCostJacobian(T - 1);
65 Eigen::MatrixXd S =
prob_->GetStateCostHessian(T - 1);
67 for (
int t = T - 2;
t > 0; --
t)
75 double q0 = dt * (
prob_->GetStateCost(
t) +
prob_->GetControlCost(
t));
77 Eigen::MatrixXd q = dt *
prob_->GetStateCostJacobian(
t);
78 Eigen::MatrixXd Q = dt *
prob_->GetStateCostHessian(
t);
79 Eigen::MatrixXd
r = dt *
prob_->GetControlCostJacobian(
t);
80 Eigen::MatrixXd R = dt *
prob_->GetControlCostHessian(
t);
81 Eigen::MatrixXd P = dt *
prob_->GetStateControlCostHessian();
83 Eigen::MatrixXd g =
r + B.transpose() *
s;
84 Eigen::MatrixXd G = P + B.transpose() * S *
A;
85 Eigen::MatrixXd H = R + B.transpose() * S * B;
89 Eigen::MatrixXd F =
prob_->get_F(
t);
90 for (
int i = 0; i < NU; ++i)
92 Eigen::MatrixXd C = std::sqrt(dt) *
prob_->GetControlNoiseJacobian(i);
93 Eigen::VectorXd c = std::sqrt(dt) * F.col(i);
95 big_C_times_little_c = big_C_times_little_c + C.transpose() * S * c;
96 big_C_times_big_C = big_C_times_big_C + C.transpose() * S * C;
97 little_c_times_little_c = little_c_times_little_c + c.transpose() * S * c;
100 g = g + big_C_times_little_c;
101 H = H + big_C_times_big_C;
105 Eigen::EigenSolver<Eigen::Matrix<double, Eigen::Dynamic, Eigen::Dynamic>> eig_solver(H);
106 auto d = eig_solver.eigenvalues();
107 auto V = eig_solver.eigenvectors();
108 Eigen::MatrixXcd D = Eigen::MatrixXcd::Zero(
d.size(),
d.size());
110 for (
int i = 0; i <
d.size(); ++i)
118 Eigen::MatrixXd H1 = (V * D * V.transpose()).
real();
131 s0 = s0 + 0.5 * little_c_times_little_c(0);
135 S = S.unaryExpr([min_clamp_, max_clamp_](
double x) ->
double {
136 return std::min(std::max(
x, min_clamp_), max_clamp_);
138 s =
s.unaryExpr([min_clamp_, max_clamp_](
double x) ->
double {
139 return std::min(std::max(
x, min_clamp_), max_clamp_);
141 s0 = std::min(std::max(s0, min_clamp_), max_clamp_);
148 const int T =
prob_->get_T();
149 const Eigen::MatrixXd control_limits =
dynamics_solver_->get_control_limits();
154 for (
int t = 0;
t < T - 1; ++
t)
156 Eigen::VectorXd u = ref_u.col(
t);
161 u.noalias() += alpha * delta_uk;
163 u = u.cwiseMax(control_limits.col(0)).cwiseMin(control_limits.col(1));
166 cost += dt * (
prob_->GetControlCost(
t) +
prob_->GetStateCost(
t));
170 cost +=
prob_->GetStateCost(T - 1);
177 Timer planning_timer, backward_pass_timer, line_search_timer;
179 prob_->DisableStochasticUpdates();
181 const int T =
prob_->get_T();
182 const int NU =
prob_->GetScene()->get_num_controls();
183 const int NX =
prob_->GetScene()->get_num_state();
188 double initial_cost = 0;
189 for (
int t = 0;
t < T - 1; ++
t)
190 initial_cost += dt * (
prob_->GetControlCost(
t) +
prob_->GetStateCost(
t));
193 initial_cost +=
prob_->GetStateCost(T - 1);
194 prob_->SetCostEvolution(0, initial_cost);
197 l_gains_.assign(T, Eigen::MatrixXd::Zero(NU, 1));
198 L_gains_.assign(T, Eigen::MatrixXd::Zero(NU, NX));
202 Eigen::MatrixXd new_U, global_best_U =
prob_->get_U();
203 solution.resize(T - 1, NU);
207 double last_cost = initial_cost, global_best_cost = initial_cost;
208 int last_best_iteration = 0;
221 backward_pass_timer.
Reset();
226 line_search_timer.
Reset();
231 const Eigen::VectorXd alpha_space = Eigen::VectorXd::LinSpaced(10, 0.1, 1.0);
232 double current_cost = 0, best_alpha = 0;
234 Eigen::MatrixXd ref_x =
prob_->get_X(),
235 ref_u =
prob_->get_U();
237 for (
int ai = 0; ai < alpha_space.rows(); ++ai)
239 double alpha = alpha_space(ai);
242 if (ai == 0 || (cost < current_cost && !std::isnan(cost)))
245 new_U =
prob_->get_U();
253 if (!new_U.allFinite() || !std::isfinite(current_cost))
262 HIGHLIGHT_NAMED(
"ILQGSolver",
"Forward pass complete in " << line_search_timer.
GetDuration() <<
" with cost: " << current_cost <<
" and alpha " << best_alpha);
267 if (global_best_cost > current_cost)
269 global_best_cost = current_cost;
270 last_best_iteration = iteration;
271 global_best_U = new_U;
276 if (iteration - last_best_iteration >
parameters_.FunctionTolerancePatience)
283 if (last_cost - current_cost < parameters_.FunctionTolerance && last_cost - current_cost > 0)
296 last_cost = current_cost;
297 for (
int t = 0;
t < T - 1; ++
t)
298 prob_->Update(new_U.col(
t),
t);
299 prob_->SetCostEvolution(iteration, current_cost);
303 for (
int t = 0;
t < T - 1; ++
t)
305 solution.row(
t) = global_best_U.col(
t).transpose();
306 prob_->Update(global_best_U.col(
t),
t);
312 prob_->EnableStochasticUpdates();
317 const Eigen::MatrixXd control_limits =
dynamics_solver_->get_control_limits();
323 return u.cwiseMax(control_limits.col(0)).cwiseMin(control_limits.col(1));