45 void AICOSolver::Instantiate(
const AICOSolverInitializer& init)
    47     std::string mode = init.SweepMode;
    48     if (mode == 
"Forwardly")
    49         sweep_mode_ = FORWARD;
    50     else if (mode == 
"Symmetric")
    51         sweep_mode_ = SYMMETRIC;
    52     else if (mode == 
"LocalGaussNewton")
    53         sweep_mode_ = LOCAL_GAUSS_NEWTON;
    54     else if (mode == 
"LocalGaussNewtonDamped")
    55         sweep_mode_ = LOCAL_GAUSS_NEWTON_DAMPED;
    58         ThrowNamed(
"Unknown sweep mode '" << init.SweepMode << 
"'");
    60     max_backtrack_iterations_ = init.MaxBacktrackIterations;
    61     minimum_step_tolerance_ = init.MinStep;
    62     step_tolerance_ = init.StepTolerance;
    63     function_tolerance_ = init.FunctionTolerance;
    64     damping_init_ = init.Damping;
    65     use_bwd_msg_ = init.UseBackwardMessage;
    66     verbose_ = init.Verbose;
    69 AICOSolver::AICOSolver() = 
default;
    71 AICOSolver::~AICOSolver() = 
default;
    75     if (problem->type() != 
"exotica::UnconstrainedTimeIndexedProblem")
    77         ThrowNamed(
"This solver can't use problem of type '" << problem->type() << 
"'!");
    79     MotionSolver::SpecifyProblem(problem);
    85 void AICOSolver::Solve(Eigen::MatrixXd& solution)
    88     prob_->ResetCostEvolution(GetNumberOfMaxIterations() + 1);
    89     prob_->termination_criterion = TerminationCriterion::NotStarted;
    92     Eigen::VectorXd q0 = prob_->ApplyStartState();
    93     std::vector<Eigen::VectorXd> q_init = prob_->GetInitialTrajectory();
    98     if (!q0.isApprox(q_init[0]))
   100         if (verbose_) 
HIGHLIGHT(
"AICO::Solve cold-started");
   101         q_init.assign(prob_->GetT(), q0);
   105         if (verbose_) 
HIGHLIGHT(
"AICO::Solve called with initial trajectory guess");
   108     prob_->SetStartState(q_init[0]);
   109     prob_->ApplyStartState();
   112     if (prob_->GetT() != last_T_) InitMessages();
   117     damping = damping_init_;
   119     if (prob_->GetT() <= 0)
   121         ThrowNamed(
"Problem has not been initialized properly: T=0!");
   123     iteration_count_ = -1;
   124     InitTrajectory(q_init);
   129     iteration_count_ = 0;
   130     while (iteration_count_ < GetNumberOfMaxIterations())
   133         if (Server::IsRos() && !
ros::ok())
   135             if (debug_) 
HIGHLIGHT(
"Solving cancelled by user");
   136             prob_->termination_criterion = TerminationCriterion::UserDefined;
   147         if (damping != 0.0 && sweep_ >= max_backtrack_iterations_)
   149             if (debug_) 
HIGHLIGHT(
"Maximum backtrack iterations reached, exiting.");
   150             prob_->termination_criterion = TerminationCriterion::BacktrackIterationLimit;
   155         if (iteration_count_ > 1)
   160             if ((damping != 0.0 && sweep_improved_cost_) || !(damping != 0.0))
   167                 if (d < minimum_step_tolerance_)
   169                     if (debug_) 
HIGHLIGHT(
"Satisfied tolerance\titer=" << iteration_count_ << 
"\td=" << d << 
"\tminimum_step_tolerance=" << minimum_step_tolerance_);
   170                     prob_->termination_criterion = TerminationCriterion::StepTolerance;
   176                 if ((cost_prev_ - cost_) <= function_tolerance_ * std::max(1.0, std::abs(cost_)))
   178                     if (debug_) 
HIGHLIGHT(
"Function tolerance achieved: " << (cost_prev_ - cost_) << 
" <= " << function_tolerance_ * std::max(1.0, std::abs(cost_)));
   179                     prob_->termination_criterion = TerminationCriterion::FunctionTolerance;
   188     if (iteration_count_ == GetNumberOfMaxIterations())
   190         if (debug_) 
HIGHLIGHT(
"Maximum iterations reached");
   191         prob_->termination_criterion = TerminationCriterion::IterationLimit;
   194     Eigen::MatrixXd sol(prob_->GetT(), prob_->N);
   195     for (
int tt = 0; tt < prob_->GetT(); ++tt)
   203 void AICOSolver::InitMessages()
   205     if (prob_ == 
nullptr) 
ThrowNamed(
"Problem definition is a NULL pointer!");
   209         ThrowNamed(
"State dimension is too small: n=" << prob_->N);
   211     if (prob_->GetT() < 2)
   213         ThrowNamed(
"Number of time steps is too small: T=" << prob_->GetT());
   216     s.assign(prob_->GetT(), Eigen::VectorXd::Zero(prob_->N));
   217     Sinv.assign(prob_->GetT(), Eigen::MatrixXd::Zero(prob_->N, prob_->N));
   218     Sinv[0].diagonal().setConstant(1e10);
   219     v.assign(prob_->GetT(), Eigen::VectorXd::Zero(prob_->N));
   220     Vinv.assign(prob_->GetT(), Eigen::MatrixXd::Zero(prob_->N, prob_->N));
   223         if (bwd_msg_v_.rows() == prob_->N && bwd_msg_Vinv_.rows() == prob_->N && bwd_msg_Vinv_.cols() == prob_->N)
   225             v[prob_->GetT() - 1] = bwd_msg_v_;
   226             Vinv[prob_->GetT() - 1] = bwd_msg_Vinv_;
   230             use_bwd_msg_ = 
false;
   231             WARNING(
"Backward message initialisation skipped, matrices have incorrect dimensions.");
   234     b.assign(prob_->GetT(), Eigen::VectorXd::Zero(prob_->N));
   235     damping_reference_.assign(prob_->GetT(), Eigen::VectorXd::Zero(prob_->N));
   236     Binv.assign(prob_->GetT(), Eigen::MatrixXd::Zero(prob_->N, prob_->N));
   237     Binv[0].setIdentity();
   238     Binv[0] = Binv[0] * 1e10;
   239     r.assign(prob_->GetT(), Eigen::VectorXd::Zero(prob_->N));
   240     R.assign(prob_->GetT(), Eigen::MatrixXd::Zero(prob_->N, prob_->N));
   241     rhat = Eigen::VectorXd::Zero(prob_->GetT());
   242     qhat.assign(prob_->GetT(), Eigen::VectorXd::Zero(prob_->N));
   245     cost_control_.resize(prob_->GetT());
   246     cost_control_.setZero();
   247     cost_task_.resize(prob_->GetT());
   248     cost_task_.setZero();
   250     q_stat_.resize(prob_->GetT());
   251     for (
int t = 0; t < prob_->GetT(); ++t)
   253         q_stat_[t].resize(prob_->N);
   257     last_T_ = prob_->GetT();
   260 void AICOSolver::InitTrajectory(
const std::vector<Eigen::VectorXd>& q_init)
   262     if (q_init.size() != 
static_cast<std::size_t
>(prob_->GetT()))
   264         ThrowNamed(
"Incorrect number of timesteps provided!");
   268     damping_reference_ = q_init;
   272     for (
int t = 1; t < prob_->GetT(); ++t)
   274         Sinv.at(t).setZero();
   275         Sinv.at(t).diagonal().setConstant(damping);
   277     for (
int t = 0; t < prob_->GetT(); ++t)
   279         Vinv.at(t).setZero();
   280         Vinv.at(t).diagonal().setConstant(damping);
   282     for (
int t = 0; t < prob_->GetT(); ++t)
   285         UpdateTaskMessage(t, b[t], 0.0);
   289     if (prob_->W.rows() != prob_->N)
   291         ThrowNamed(prob_->W.rows() << 
"!=" << prob_->N);
   298     cost_ = EvaluateTrajectory(b, 
true);  
   300     prob_->SetCostEvolution(0, cost_);
   301     if (cost_ < 0) 
ThrowNamed(
"Invalid cost! " << cost_);
   302     if (debug_) 
HIGHLIGHT(
"Initial cost, updates: " << update_count_ << 
", cost_(ctrl/task/total): " << cost_control_.sum() << 
"/" << cost_task_.sum() << 
"/" << cost_);
   306 void AICOSolver::UpdateFwdMessage(
int t)
   308     Eigen::MatrixXd barS(prob_->N, prob_->N), St;
   310     s[t] = barS * (Sinv[t - 1] * 
s[t - 1] + 
r[t - 1]);
   315 void AICOSolver::UpdateBwdMessage(
int t)
   317     Eigen::MatrixXd barV(prob_->N, prob_->N), Vt;
   318     if (t < prob_->GetT() - 1)
   321         v[t] = barV * (Vinv[t + 1] * v[t + 1] + 
r[t + 1]);
   325     if (t == prob_->GetT() - 1)
   330             Vinv[t].diagonal().setConstant(1);
   334             v[prob_->GetT() - 1] = bwd_msg_v_;
   335             Vinv[prob_->GetT() - 1] = bwd_msg_Vinv_;
   340 void AICOSolver::UpdateTaskMessage(
int t,
   341                                    const Eigen::Ref<const Eigen::VectorXd>& qhat_t, 
double tolerance,
   342                                    double max_step_size)
   344     Eigen::VectorXd 
diff = qhat_t - qhat[t];
   345     if ((diff.array().abs().maxCoeff() < tolerance)) 
return;
   346     double nrm = diff.norm();
   347     if (max_step_size > 0. && nrm > max_step_size)
   349         qhat[t] += diff * (max_step_size / nrm);
   356     prob_->Update(qhat[t], t);
   358     double c = GetTaskCosts(t);
   359     q_stat_[t].addw(c > 0 ? 1.0 / (1.0 + c) : 1.0, qhat_t);
   362 double AICOSolver::GetTaskCosts(
int t)
   370     for (
int i = 0; i < prob_->cost.num_tasks; ++i)
   372         prec = prob_->cost.rho[t](i);
   375             int start = prob_->cost.indexing[i].start_jacobian;
   376             int len = prob_->cost.indexing[i].length_jacobian;
   377             Jt = prob_->cost.jacobian[t].middleRows(start, len).transpose();
   378             C += prec * (prob_->cost.ydiff[t].segment(start, len)).squaredNorm();
   379             R[t] += prec * Jt * prob_->cost.jacobian[t].middleRows(start, len);
   380             r[t] += prec * Jt * (-prob_->cost.ydiff[t].segment(start, len) + prob_->cost.jacobian[t].middleRows(start, len) * qhat[t]);
   381             rhat[t] += prec * (-prob_->cost.ydiff[t].segment(start, len) + prob_->cost.jacobian[t].middleRows(start, len) * qhat[t]).squaredNorm();
   384     return prob_->get_ct() * C;
   387 void AICOSolver::UpdateTimestep(
int t, 
bool update_fwd, 
bool update_bwd,
   388                                 int max_relocation_iterations, 
double tolerance, 
bool force_relocation,
   389                                 double max_step_size)
   391     if (update_fwd) UpdateFwdMessage(t);
   392     if (update_bwd) UpdateBwdMessage(t);
   396         Binv[t] = Sinv[t] + Vinv[t] + R[t] + Eigen::MatrixXd::Identity(prob_->N, prob_->N) * damping;
   397         AinvBSymPosDef(b[t], Binv[t], Sinv[t] * 
s[t] + Vinv[t] * v[t] + 
r[t] + damping * damping_reference_[t]);
   401         Binv[t] = Sinv[t] + Vinv[t] + R[t];
   405     for (
int k = 0; k < max_relocation_iterations && !(Server::IsRos() && !
ros::ok()); ++k)
   407         if (!((!k && force_relocation) || (b[t] - qhat[t]).array().abs().maxCoeff() > tolerance)) 
break;
   409         UpdateTaskMessage(t, b.at(t), 0., max_step_size);
   412         if (update_fwd) UpdateFwdMessage(t);
   413         if (update_bwd) UpdateBwdMessage(t);
   417             Binv[t] = Sinv[t] + Vinv[t] + R[t] + Eigen::MatrixXd::Identity(prob_->N, prob_->N) * damping;
   418             AinvBSymPosDef(b[t], Binv[t], Sinv[t] * 
s[t] + Vinv[t] * v[t] + 
r[t] + damping * damping_reference_[t]);
   422             Binv[t] = Sinv[t] + Vinv[t] + R[t];
   428 void AICOSolver::UpdateTimestepGaussNewton(
int t, 
bool update_fwd,
   429                                            bool update_bwd, 
int max_relocation_iterations, 
double tolerance,
   430                                            double max_step_size)
   436 double AICOSolver::EvaluateTrajectory(
const std::vector<Eigen::VectorXd>& x,
   439     if (verbose_) 
ROS_WARN_STREAM(
"Evaluating, iteration " << iteration_count_ << 
", sweep " << sweep_);
   447         for (
int t = 0; t < prob_->GetT(); ++t)
   450             if (!q[t].allFinite())
   452                 ThrowNamed(
"q[" << t << 
"] is not finite: " << q[t].transpose());
   454             prob_->Update(q[t], t);
   459     for (
int t = 1; t < prob_->GetT(); ++t)
   461         if (Server::IsRos() && !
ros::ok()) 
return -1.0;
   464         cost_control_(t) = prob_->GetScalarTransitionCost(t);
   467         cost_task_(t) = prob_->GetScalarTaskCost(t);
   470     cost_ = cost_control_.sum() + cost_task_.sum();
   474 double AICOSolver::Step()
   482             for (t = 1; t < prob_->GetT(); ++t)
   484                 UpdateTimestep(t, 
true, 
false, 1, minimum_step_tolerance_, !iteration_count_, 1.);  
   486             for (t = prob_->GetT() - 2; t > 0; t--)
   488                 UpdateTimestep(t, 
false, 
true, 0, minimum_step_tolerance_, 
false, 1.);  
   493             for (t = 1; t < prob_->GetT(); ++t)
   495                 UpdateTimestep(t, 
true, 
false, 1, minimum_step_tolerance_, !iteration_count_, 1.);  
   498             for (t = prob_->GetT() - 2; t > 0; t--)
   500                 UpdateTimestep(t, 
false, 
true, (iteration_count_ ? 1 : 0), minimum_step_tolerance_, 
false, 1.);
   503         case LOCAL_GAUSS_NEWTON:
   504             for (t = 1; t < prob_->GetT(); ++t)
   506                 UpdateTimestep(t, 
true, 
false, (iteration_count_ ? 5 : 1), minimum_step_tolerance_, !iteration_count_, 1.);  
   508             for (t = prob_->GetT() - 2; t > 0; t--)
   510                 UpdateTimestep(t, 
false, 
true, (iteration_count_ ? 5 : 0), minimum_step_tolerance_, 
false, 1.);  
   513         case LOCAL_GAUSS_NEWTON_DAMPED:
   514             for (t = 1; t < prob_->GetT(); ++t)
   516                 UpdateTimestepGaussNewton(t, 
true, 
false, (iteration_count_ ? 5 : 1),
   517                                           minimum_step_tolerance_, 1.);  
   519             for (t = prob_->GetT() - 2; t > 0; t--)
   521                 UpdateTimestep(t, 
false, 
true, (iteration_count_ ? 5 : 0), minimum_step_tolerance_, 
false, 1.);
   528     for (t = 0; t < static_cast<int>(b.size()); ++t)
   530         b_step_ = std::max((b_old[t] - b[t]).array().
abs().maxCoeff(), b_step_);
   532     damping_reference_ = b;
   534     cost_ = EvaluateTrajectory(b);
   537         HIGHLIGHT(
"Iteration: " << iteration_count_ << 
", Sweep: " << sweep_ << 
", updates: " << update_count_ << 
", cost(ctrl/task/total): " << cost_control_.sum() << 
"/" << cost_task_.sum() << 
"/" << cost_ << 
" (dq=" << b_step_ << 
", damping=" << damping << 
")");
   539     else if (debug_ && sweep_ == 0)
   541         HIGHLIGHT(
"Iteration: " << iteration_count_ << 
", updates: " << update_count_ << 
", cost(ctrl/task/total): " << cost_control_.sum() << 
"/" << cost_task_.sum() << 
"/" << cost_ << 
" (dq=" << b_step_ << 
", damping=" << damping << 
")");
   543     if (cost_ < 0) 
return -1.0;
   544     best_sweep_ = sweep_;
   547     if (damping != 0.0) PerhapsUndoStep();
   550     if (sweep_improved_cost_)
   555         prob_->SetCostEvolution(iteration_count_, cost_);
   561 void AICOSolver::RememberOldState()
   576     cost_control_old_ = cost_control_;
   577     cost_task_old_ = cost_task_;
   578     best_sweep_old_ = best_sweep_;
   579     b_step_old_ = b_step_;
   582 void AICOSolver::PerhapsUndoStep()
   584     if (cost_ > cost_old_)
   586         sweep_improved_cost_ = 
false;
   601         damping_reference_ = b_old;
   602         cost_control_ = cost_control_old_;
   603         cost_task_ = cost_task_old_;
   604         best_sweep_ = best_sweep_old_;
   605         b_step_ = b_step_old_;
   606         if (verbose_) 
HIGHLIGHT(
"Reverting to previous line-search step (" << best_sweep_ << 
")");
   610         sweep_improved_cost_ = 
true;
 
static void AinvBSymPosDef(T1 &x, const T2 &A, const T3 &b)
Computes the solution to the linear problem  for symmetric positive definite matrix A...
Solves motion planning problem using Approximate Inference Control method. 
IMETHOD Vector diff(const Vector &p_w_a, const Vector &p_w_b, double dt=1)
#define REGISTER_MOTIONSOLVER_TYPE(TYPE, DERIV)
#define ROS_WARN_STREAM(args)
static void inverseSymPosDef(T1 &Ainv, const T2 &A)
Computes an inverse of a symmetric positive definite matrix. 
INLINE Rall1d< T, V, S > abs(const Rall1d< T, V, S > &x)
Approximate Inference Control. 
double GetDuration() const 
std::shared_ptr< PlanningProblem > PlanningProblemPtr