9#include "crocoddyl/core/solvers/intro.hpp" 
   13#include "crocoddyl/core/utils/exception.hpp" 
   14#include "crocoddyl/core/utils/stop-watch.hpp" 
   24      zero_upsilon_(false) {
 
   25  const std::size_t T = problem_->get_T();
 
   44  const std::size_t ndx = problem_->get_ndx();
 
   45  const std::vector<std::shared_ptr<ActionModelAbstract> >& models =
 
   46      problem_->get_runningModels();
 
   47  for (std::size_t t = 0; t < T; ++t) {
 
   48    const std::shared_ptr<ActionModelAbstract>& model = models[t];
 
   49    const std::size_t nu = model->get_nu();
 
   50    const std::size_t nh = model->get_nh();
 
   52    KQuu_tmp_[t] = Eigen::MatrixXd::Zero(ndx, nu);
 
   53    YZ_[t] = Eigen::MatrixXd::Zero(nu, nu);
 
   54    Hy_[t] = Eigen::MatrixXd::Zero(nh, nh);
 
   55    Qz_[t] = Eigen::VectorXd::Zero(nh);
 
   56    Qzz_[t] = Eigen::MatrixXd::Zero(nh, nh);
 
   57    Qxz_[t] = Eigen::MatrixXd::Zero(ndx, nh);
 
   58    Quz_[t] = Eigen::MatrixXd::Zero(nu, nh);
 
   59    kz_[t] = Eigen::VectorXd::Zero(nu);
 
   60    Kz_[t] = Eigen::MatrixXd::Zero(nu, ndx);
 
   61    ks_[t] = Eigen::VectorXd::Zero(nh);
 
   62    Ks_[t] = Eigen::MatrixXd::Zero(nh, ndx);
 
   63    QuuinvHuT_[t] = Eigen::MatrixXd::Zero(nu, nh);
 
   64    Qzz_llt_[t] = Eigen::LLT<Eigen::MatrixXd>(nh);
 
   65    Hu_lu_[t] = Eigen::FullPivLU<Eigen::MatrixXd>(nh, nu);
 
   66    Hu_qr_[t] = Eigen::ColPivHouseholderQR<Eigen::MatrixXd>(nu, nh);
 
   67    Hy_lu_[t] = Eigen::PartialPivLU<Eigen::MatrixXd>(nh);
 
 
   71SolverIntro::~SolverIntro() {}
 
   73bool SolverIntro::solve(
const std::vector<Eigen::VectorXd>& init_xs,
 
   74                        const std::vector<Eigen::VectorXd>& init_us,
 
   75                        const std::size_t maxiter, 
const bool is_feasible,
 
   76                        const double init_reg) {
 
   77  START_PROFILER(
"SolverIntro::solve");
 
   78  if (problem_->is_updated()) {
 
   83  setCandidate(init_xs, init_us, is_feasible);
 
   85  if (std::isnan(init_reg)) {
 
   92  was_feasible_ = 
false;
 
   97  bool recalcDiff = 
true;
 
   98  for (iter_ = 0; iter_ < maxiter; ++iter_) {
 
  101        computeDirection(recalcDiff);
 
  102      } 
catch (std::exception& e) {
 
  104        increaseRegularization();
 
  105        if (preg_ == reg_max_) {
 
  119    if (hfeas_ != 0 && iter_ != 0) {
 
  121          std::max(
upsilon_, (d_[0] + .5 * d_[1]) / ((1 - 
rho_) * hfeas_));
 
  126    for (std::vector<double>::const_iterator it = alphas_.begin();
 
  127         it != alphas_.end(); ++it) {
 
  130        dV_ = tryStep(steplength_);
 
  131        dfeas_ = hfeas_ - hfeas_try_;
 
  133      } 
catch (std::exception& e) {
 
  137      dVexp_ = steplength_ * (d_[0] + 0.5 * steplength_ * d_[1]);
 
  138      dPhiexp_ = dVexp_ + steplength_ * 
upsilon_ * dfeas_;
 
  140        if (std::abs(d_[0]) < th_grad_ || dPhi_ > th_acceptstep_ * dPhiexp_) {
 
  141          was_feasible_ = is_feasible_;
 
  142          setCandidate(xs_try_, us_try_, (was_feasible_) || (steplength_ == 1));
 
  152          was_feasible_ = is_feasible_;
 
  153          setCandidate(xs_try_, us_try_, (was_feasible_) || (steplength_ == 1));
 
  164    const std::size_t n_callbacks = callbacks_.size();
 
  165    for (std::size_t c = 0; c < n_callbacks; ++c) {
 
  166      CallbackAbstract& callback = *callbacks_[c];
 
  170    if (steplength_ > th_stepdec_ && dV_ >= 0.) {
 
  171      decreaseRegularization();
 
  173    if (steplength_ <= th_stepinc_ || std::abs(d_[1]) <= 
th_feas_) {
 
  174      if (preg_ == reg_max_) {
 
  175        STOP_PROFILER(
"SolverIntro::solve");
 
  178      increaseRegularization();
 
  181    if (is_feasible_ && stop_ < th_stop_) {
 
  182      STOP_PROFILER(
"SolverIntro::solve");
 
  186  STOP_PROFILER(
"SolverIntro::solve");
 
  190double SolverIntro::tryStep(
const double steplength) {
 
  191  forwardPass(steplength);
 
  192  hfeas_try_ = computeEqualityFeasibility();
 
  193  return cost_ - cost_try_;
 
  196double SolverIntro::stoppingCriteria() {
 
  197  stop_ = std::max(hfeas_, std::abs(d_[0] + 0.5 * d_[1]));
 
  201void SolverIntro::resizeData() {
 
  202  START_PROFILER(
"SolverIntro::resizeData");
 
  203  SolverFDDP::resizeData();
 
  205  const std::size_t T = problem_->get_T();
 
  206  const std::size_t ndx = problem_->get_ndx();
 
  207  const std::vector<std::shared_ptr<ActionModelAbstract> >& models =
 
  208      problem_->get_runningModels();
 
  209  for (std::size_t t = 0; t < T; ++t) {
 
  210    const std::shared_ptr<ActionModelAbstract>& model = models[t];
 
  211    const std::size_t nu = model->get_nu();
 
  212    const std::size_t nh = model->get_nh();
 
  213    KQuu_tmp_[t].conservativeResize(ndx, nu);
 
  214    YZ_[t].conservativeResize(nu, nu);
 
  215    Hy_[t].conservativeResize(nh, nh);
 
  216    Qz_[t].conservativeResize(nh);
 
  217    Qzz_[t].conservativeResize(nh, nh);
 
  218    Qxz_[t].conservativeResize(ndx, nh);
 
  219    Quz_[t].conservativeResize(nu, nh);
 
  220    kz_[t].conservativeResize(nu);
 
  221    Kz_[t].conservativeResize(nu, ndx);
 
  222    ks_[t].conservativeResize(nh);
 
  223    Ks_[t].conservativeResize(nh, ndx);
 
  224    QuuinvHuT_[t].conservativeResize(nu, nh);
 
  226  STOP_PROFILER(
"SolverIntro::resizeData");
 
  229double SolverIntro::calcDiff() {
 
  230  START_PROFILER(
"SolverIntro::calcDiff");
 
  231  SolverFDDP::calcDiff();
 
  232  const std::size_t T = problem_->get_T();
 
  233  const std::vector<std::shared_ptr<ActionModelAbstract> >& models =
 
  234      problem_->get_runningModels();
 
  235  const std::vector<std::shared_ptr<ActionDataAbstract> >& datas =
 
  236      problem_->get_runningDatas();
 
  239#ifdef CROCODDYL_WITH_MULTITHREADING 
  240#pragma omp parallel for num_threads(problem_->get_nthreads()) 
  242      for (std::size_t t = 0; t < T; ++t) {
 
  243        const std::shared_ptr<crocoddyl::ActionModelAbstract>& model =
 
  245        const std::shared_ptr<crocoddyl::ActionDataAbstract>& data = datas[t];
 
  246        if (model->get_nu() > 0 && model->get_nh() > 0) {
 
  247          Hu_lu_[t].compute(data->Hu);
 
  250          const Eigen::Block<Eigen::MatrixXd, Eigen::Dynamic, Eigen::Dynamic,
 
  253          Hy_[t].noalias() = data->Hu * Y;
 
  255          const Eigen::Inverse<Eigen::PartialPivLU<Eigen::MatrixXd> > Hy_inv =
 
  257          ks_[t].noalias() = Hy_inv * data->h;
 
  258          Ks_[t].noalias() = Hy_inv * data->Hx;
 
  259          kz_[t].noalias() = Y * 
ks_[t];
 
  260          Kz_[t].noalias() = Y * 
Ks_[t];
 
  265#ifdef CROCODDYL_WITH_MULTITHREADING 
  266#pragma omp parallel for num_threads(problem_->get_nthreads()) 
  268      for (std::size_t t = 0; t < T; ++t) {
 
  269        const std::shared_ptr<crocoddyl::ActionModelAbstract>& model =
 
  271        const std::shared_ptr<crocoddyl::ActionDataAbstract>& data = datas[t];
 
  272        if (model->get_nu() > 0 && model->get_nh() > 0) {
 
  273          Hu_qr_[t].compute(data->Hu.transpose());
 
  276          const Eigen::Block<Eigen::MatrixXd, Eigen::Dynamic, Eigen::Dynamic,
 
  279          Hy_[t].noalias() = data->Hu * Y;
 
  281          const Eigen::Inverse<Eigen::PartialPivLU<Eigen::MatrixXd> > Hy_inv =
 
  283          ks_[t].noalias() = Hy_inv * data->h;
 
  284          Ks_[t].noalias() = Hy_inv * data->Hx;
 
  285          kz_[t].noalias() = Y * 
ks_[t];
 
  286          Kz_[t].noalias() = Y * 
Ks_[t];
 
  294  STOP_PROFILER(
"SolverIntro::calcDiff");
 
  298void SolverIntro::computeValueFunction(
 
  299    const std::size_t t, 
const std::shared_ptr<ActionModelAbstract>& model) {
 
  300  const std::size_t nu = model->get_nu();
 
  304    START_PROFILER(
"SolverIntro::Vx");
 
  305    Quuk_[t].noalias() = Quu_[t] * k_[t];
 
  306    Vx_[t].noalias() -= Qxu_[t] * k_[t];
 
  308    Vx_[t].noalias() -= K_[t].transpose() * Qu_[t];
 
  310    STOP_PROFILER(
"SolverIntro::Vx");
 
  311    START_PROFILER(
"SolverIntro::Vxx");
 
  312    KQuu_tmp_[t].noalias() = K_[t].transpose() * Quu_[t];
 
  313    KQuu_tmp_[t].noalias() -= 2 * Qxu_[t];
 
  314    Vxx_[t].noalias() += KQuu_tmp_[t] * K_[t];
 
  315    STOP_PROFILER(
"SolverIntro::Vxx");
 
  317  Vxx_tmp_ = 0.5 * (Vxx_[t] + Vxx_[t].transpose());
 
  320  if (!std::isnan(preg_)) {
 
  321    Vxx_[t].diagonal().array() += preg_;
 
  326    Vx_[t].noalias() += Vxx_[t] * fs_[t];
 
  330void SolverIntro::computeGains(
const std::size_t t) {
 
  331  START_PROFILER(
"SolverIntro::computeGains");
 
  332  const std::shared_ptr<crocoddyl::ActionModelAbstract>& model =
 
  333      problem_->get_runningModels()[t];
 
  334  const std::shared_ptr<crocoddyl::ActionDataAbstract>& data =
 
  335      problem_->get_runningDatas()[t];
 
  337  const std::size_t nu = model->get_nu();
 
  338  const std::size_t nh = model->get_nh();
 
  342      if (nu > 0 && nh > 0) {
 
  343        START_PROFILER(
"SolverIntro::Qzz_inv");
 
  344        const std::size_t rank = 
Hu_rank_[t];
 
  345        const std::size_t nullity = data->Hu.cols() - rank;
 
  346        const Eigen::Block<Eigen::MatrixXd, Eigen::Dynamic, Eigen::Dynamic,
 
  348            Z = 
YZ_[t].rightCols(nullity);
 
  349        Quz_[t].noalias() = Quu_[t] * Z;
 
  350        Qzz_[t].noalias() = Z.transpose() * 
Quz_[t];
 
  352        STOP_PROFILER(
"SolverIntro::Qzz_inv");
 
  353        const Eigen::ComputationInfo& info = 
Qzz_llt_[t].info();
 
  354        if (info != Eigen::Success) {
 
  355          throw_pretty(
"backward error");
 
  360        Eigen::Transpose<Eigen::MatrixXd> QzzinvQzu = 
Quz_[t].transpose();
 
  361        Qzz_llt_[t].solveInPlace(QzzinvQzu);
 
  362        Qz_[t].noalias() = Z.transpose() * Qu_[t];
 
  364        Qxz_[t].noalias() = Qxu_[t] * Z;
 
  365        Eigen::Transpose<Eigen::MatrixXd> Qzx = 
Qxz_[t].transpose();
 
  367        Qz_[t].noalias() -= QzzinvQzu * 
kz_[t];
 
  368        Qzx.noalias() -= QzzinvQzu * 
Kz_[t];
 
  369        k_[t].noalias() += Z * 
Qz_[t];
 
  370        K_[t].noalias() += Z * Qzx;
 
  372        SolverFDDP::computeGains(t);
 
  376      SolverFDDP::computeGains(t);
 
  377      if (nu > 0 && nh > 0) {
 
  378        START_PROFILER(
"SolverIntro::Qzz_inv");
 
  379        QuuinvHuT_[t] = data->Hu.transpose();
 
  380        Quu_llt_[t].solveInPlace(QuuinvHuT_[t]);
 
  381        Qzz_[t].noalias() = data->Hu * QuuinvHuT_[t];
 
  383        STOP_PROFILER(
"SolverIntro::Qzz_inv");
 
  384        const Eigen::ComputationInfo& info = 
Qzz_llt_[t].info();
 
  385        if (info != Eigen::Success) {
 
  386          throw_pretty(
"backward error");
 
  388        Eigen::Transpose<Eigen::MatrixXd> HuQuuinv = QuuinvHuT_[t].transpose();
 
  391        ks_[t].noalias() -= data->Hu * k_[t];
 
  393        Ks_[t].noalias() -= data->Hu * K_[t];
 
  394        k_[t].noalias() += QuuinvHuT_[t] * 
ks_[t];
 
  395        K_[t] += QuuinvHuT_[t] * 
Ks_[t];
 
  399  STOP_PROFILER(
"SolverIntro::computeGains");
 
  414const std::vector<std::size_t>& SolverIntro::get_Hu_rank()
 const {
 
  451  if (0. >= rho || rho > 1.) {
 
  452    throw_pretty(
"Invalid argument: " << 
"rho value should between 0 and 1.");
 
 
Feasibility-driven Differential Dynamic Programming (FDDP) solver.
 
virtual const Eigen::Vector2d & expectedImprovement()
Return the expected improvement  from a given current search direction .
 
void updateExpectedImprovement()
Update internal values for computing the expected improvement.
 
std::vector< Eigen::MatrixXd > Kz_
Feedback gain in the nullspace of .
 
std::vector< Eigen::FullPivLU< Eigen::MatrixXd > > Hu_lu_
 
std::vector< Eigen::MatrixXd > Hy_
 
double th_feas_
Threshold for switching to feasibility.
 
std::vector< std::size_t > Hu_rank_
Rank of the control Jacobian of the equality constraints.
 
std::vector< Eigen::MatrixXd > Qxz_
Hessian of the reduced Hamiltonian .
 
std::vector< Eigen::VectorXd > Qz_
Jacobian of the reduced Hamiltonian .
 
double get_th_feas() const
Return the threshold for switching to feasibility.
 
const std::vector< Eigen::VectorXd > & get_kz() const
Return feedforward term related to the nullspace of .
 
EqualitySolverType get_equality_solver() const
Return the type of solver used for handling the equality constraints.
 
const std::vector< Eigen::MatrixXd > & get_YZ() const
Return the rank of control-equality constraints \mathbf{H_u}\f.
 
const std::vector< Eigen::MatrixXd > & get_Kz() const
Return feedback gain related to the nullspace of .
 
void set_equality_solver(const EqualitySolverType type)
Modify the type of solver used for handling the equality constraints.
 
std::vector< Eigen::MatrixXd > Quz_
Hessian of the reduced Hamiltonian .
 
std::vector< Eigen::MatrixXd > Ks_
Feedback gain related to the equality constraints.
 
std::vector< Eigen::LLT< Eigen::MatrixXd > > Qzz_llt_
Cholesky LLT solver.
 
std::vector< Eigen::ColPivHouseholderQR< Eigen::MatrixXd > > Hu_qr_
 
std::vector< Eigen::MatrixXd > Qzz_
Hessian of the reduced Hamiltonian .
 
void set_zero_upsilon(const bool zero_upsilon)
Modify the zero-upsilon label.
 
EIGEN_MAKE_ALIGNED_OPERATOR_NEW SolverIntro(std::shared_ptr< ShootingProblem > problem)
Initialize the INTRO solver.
 
const std::vector< Eigen::MatrixXd > & get_Hy() const
Return span-projected Jacobian of the equality-constraint with respect to the control.
 
double get_rho() const
Return the rho parameter used in the merit function.
 
const std::vector< Eigen::MatrixXd > & get_Qxz() const
Return Hessian of the reduced Hamiltonian .
 
const std::vector< Eigen::MatrixXd > & get_Ks() const
Return feedback gain related to the equality constraints.
 
void set_th_feas(const double th_feas)
Modify the threshold for switching to feasibility.
 
bool get_zero_upsilon() const
Return the zero-upsilon label.
 
double get_upsilon() const
Return the estimated penalty parameter that balances relative contribution of the cost function and e...
 
std::vector< Eigen::MatrixXd > YZ_
 
const std::vector< Eigen::MatrixXd > & get_Quz() const
Return Hessian of the reduced Hamiltonian .
 
enum EqualitySolverType eq_solver_
Strategy used for handling the equality constraints.
 
const std::vector< Eigen::MatrixXd > & get_Qzz() const
Return Hessian of the reduced Hamiltonian .
 
std::vector< Eigen::VectorXd > kz_
Feedforward term in the nullspace of .
 
const std::vector< Eigen::VectorXd > & get_ks() const
Return feedforward term related to the equality constraints.
 
const std::vector< Eigen::VectorXd > & get_Qz() const
Return Jacobian of the reduced Hamiltonian .
 
std::vector< Eigen::PartialPivLU< Eigen::MatrixXd > > Hy_lu_
 
std::vector< Eigen::VectorXd > ks_
Feedforward term related to the equality constraints.
 
void set_rho(const double rho)
Modify the rho parameter used in the merit function.