control_limited_ddp_solver.cpp
Go to the documentation of this file.
1 //
2 // Copyright (c) 2019-2020, University of Edinburgh, University of Oxford
3 // All rights reserved.
4 //
5 // Redistribution and use in source and binary forms, with or without
6 // modification, are permitted provided that the following conditions are met:
7 //
8 // * Redistributions of source code must retain the above copyright notice,
9 // this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above copyright
11 // notice, this list of conditions and the following disclaimer in the
12 // documentation and/or other materials provided with the distribution.
13 // * Neither the name of nor the names of its contributors may be used to
14 // endorse or promote products derived from this software without specific
15 // prior written permission.
16 //
17 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
18 // AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 // IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 // ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
21 // LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
22 // CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
23 // SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
24 // INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
25 // CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
26 // ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
27 // POSSIBILITY OF SUCH DAMAGE.
28 //
29 
33 
35 
36 namespace exotica
37 {
38 void ControlLimitedDDPSolver::Instantiate(const ControlLimitedDDPSolverInitializer& init)
39 {
40  parameters_ = init;
41  base_parameters_ = AbstractDDPSolverInitializer(ControlLimitedDDPSolverInitializer(parameters_));
42 }
43 
44 void ControlLimitedDDPSolver::BackwardPass()
45 {
46  const Eigen::MatrixXd& control_limits = dynamics_solver_->get_control_limits();
47 
48  Vx_.back().noalias() = prob_->GetStateCostJacobian(T_ - 1);
49  Vxx_.back().noalias() = prob_->GetStateCostHessian(T_ - 1);
50 
51  // concatenation axis for tensor products
52  // See https://eigen.tuxfamily.org/dox-devel/unsupported/eigen_tensors.html#title14
53  Eigen::array<Eigen::IndexPair<int>, 1> dims = {Eigen::IndexPair<int>(1, 0)};
54 
55  Eigen::VectorXd x(NX_), u(NU_); // TODO: Replace
56  for (int t = T_ - 2; t >= 0; t--)
57  {
58  x = prob_->get_X(t);
59  u = prob_->get_U(t);
60 
61  dynamics_solver_->ComputeDerivatives(x, u);
62  fx_[t].noalias() = dynamics_solver_->get_Fx();
63  fu_[t].noalias() = dynamics_solver_->get_Fu();
64 
65  Qx_[t].noalias() = dt_ * prob_->GetStateCostJacobian(t) + fx_[t].transpose() * Vx_[t + 1];
66  Qu_[t].noalias() = dt_ * prob_->GetControlCostJacobian(t) + fu_[t].transpose() * Vx_[t + 1];
67 
68  // State regularization
69  Vxx_[t + 1].diagonal().array() += lambda_;
70 
71  Qxx_[t].noalias() = dt_ * prob_->GetStateCostHessian(t) + fx_[t].transpose() * Vxx_[t + 1] * fx_[t];
72  Quu_[t].noalias() = dt_ * prob_->GetControlCostHessian(t) + fu_[t].transpose() * Vxx_[t + 1] * fu_[t];
73  // Qux_[t].noalias() = dt_ * prob_->GetStateControlCostHessian() // TODO: Reactivate once we have costs that depend on both x and u!
74  Qux_[t].noalias() = fu_[t].transpose() * Vxx_[t + 1] * fx_[t];
75 
76  if (parameters_.UseSecondOrderDynamics && dynamics_solver_->get_has_second_order_derivatives())
77  {
78  Eigen::Tensor<double, 1> Vx_tensor = Eigen::TensorMap<Eigen::Tensor<double, 1>>(Vx_[t + 1].data(), NDX_);
79  Qxx_[t].noalias() += Eigen::TensorToMatrix((Eigen::Tensor<double, 2>)dynamics_solver_->fxx(x, u).contract(Vx_tensor, dims), NDX_, NDX_) * dt_;
80  Quu_[t].noalias() += Eigen::TensorToMatrix((Eigen::Tensor<double, 2>)dynamics_solver_->fuu(x, u).contract(Vx_tensor, dims), NU_, NU_) * dt_;
81  Qux_[t].noalias() += Eigen::TensorToMatrix((Eigen::Tensor<double, 2>)dynamics_solver_->fxu(x, u).contract(Vx_tensor, dims), NU_, NDX_) * dt_;
82  }
83 
84  Eigen::VectorXd low_limit = control_limits.col(0) - u,
85  high_limit = control_limits.col(1) - u;
86 
87  // Quu_.diagonal().array() += lambda_;
88  BoxQPSolution boxqp_sol;
89  if (parameters_.UseNewBoxQP)
90  {
91  boxqp_sol = BoxQP(Quu_[t], Qu_[t], low_limit, high_limit, u, 0.1, 100, 1e-5, lambda_, parameters_.BoxQPUsePolynomialLinesearch, parameters_.BoxQPUseCholeskyFactorization);
92  }
93  else
94  {
95  boxqp_sol = ExoticaBoxQP(Quu_[t], Qu_[t], low_limit, high_limit, u, 0.1, 100, 1e-5, lambda_, parameters_.BoxQPUsePolynomialLinesearch, parameters_.BoxQPUseCholeskyFactorization);
96  }
97 
98  Quu_inv_[t].setZero();
99  if (boxqp_sol.free_idx.size() > 0)
100  for (std::size_t i = 0; i < boxqp_sol.free_idx.size(); ++i)
101  for (std::size_t j = 0; j < boxqp_sol.free_idx.size(); ++j)
102  Quu_inv_[t](boxqp_sol.free_idx[i], boxqp_sol.free_idx[j]) = boxqp_sol.Hff_inv(i, j);
103 
104  // Compute controls
105  K_[t].noalias() = -Quu_inv_[t] * Qux_[t];
106  k_[t].noalias() = boxqp_sol.x;
107 
108  // Update the value function w.r.t. u as k (feed-forward term) is clamped inside the BoxQP
109  if (boxqp_sol.free_idx.size() > 0)
110  for (std::size_t i = 0; i < boxqp_sol.clamped_idx.size(); ++i)
111  Qu_[t](boxqp_sol.clamped_idx[i]) = 0.;
112 
113  Vx_[t].noalias() = Qx_[t] + K_[t].transpose() * Quu_[t] * k_[t] + K_[t].transpose() * Qu_[t] + Qux_[t].transpose() * k_[t]; // Eq. 25(b)
114  Vxx_[t].noalias() = Qxx_[t] + K_[t].transpose() * Quu_[t] * K_[t] + K_[t].transpose() * Qux_[t] + Qux_[t].transpose() * K_[t]; // Eq. 25(c)
115  Vxx_[t] = 0.5 * (Vxx_[t] + Vxx_[t].transpose()).eval(); // Ensure the Hessian of the value function is symmetric.
116  }
117 }
118 
119 } // namespace exotica
Eigen::MatrixXd Hff_inv
#define REGISTER_MOTIONSOLVER_TYPE(TYPE, DERIV)
std::vector< size_t > clamped_idx
Eigen::VectorXd x
std::vector< size_t > free_idx
MatrixType< Scalar > TensorToMatrix(const Eigen::Tensor< Scalar, rank > &tensor, const sizeType rows, const sizeType cols)
double x
BoxQPSolution ExoticaBoxQP(const Eigen::MatrixXd &H, const Eigen::VectorXd &q, const Eigen::VectorXd &b_low, const Eigen::VectorXd &b_high, const Eigen::VectorXd &x_init, const double gamma, const int max_iterations, const double epsilon, const double lambda, bool use_polynomial_linesearch=false, bool use_cholesky_factorization=false)
BoxQPSolution BoxQP(const Eigen::MatrixXd &H, const Eigen::VectorXd &q, const Eigen::VectorXd &b_low, const Eigen::VectorXd &b_high, const Eigen::VectorXd &x_init, const double th_acceptstep, const int max_iterations, const double th_gradient_tolerance, const double lambda, bool use_polynomial_linesearch=true, bool use_cholesky_factorization=true)


exotica_ddp_solver
Author(s): Traiko Dinev
autogenerated on Sat Apr 10 2021 02:36:21