- 3.0.2 core module.
SensitivityIntegrator.h
Go to the documentation of this file.
1 /**********************************************************************************************************************
2 This file is part of the Control Toolbox (https://github.com/ethz-adrl/control-toolbox), copyright by ETH Zurich.
3 Licensed under the BSD-2 license (see LICENSE file in main directory)
4 **********************************************************************************************************************/
5 
6 #pragma once
7 
11 
12 #define SYMPLECTIC_ENABLED \
13  template <size_t V, size_t P> \
14  typename std::enable_if<(V > 0 && P > 0), void>::type
15 #define SYMPLECTIC_DISABLED \
16  template <size_t V, size_t P> \
17  typename std::enable_if<(V <= 0 || P <= 0), void>::type
18 
19 namespace ct {
20 namespace core {
21 
22 
32 template <size_t STATE_DIM,
33  size_t CONTROL_DIM,
34  size_t P_DIM = STATE_DIM / 2,
35  size_t V_DIM = STATE_DIM / 2,
36  typename SCALAR = double>
37 class SensitivityIntegrator : public Sensitivity<STATE_DIM, CONTROL_DIM, SCALAR>
38 {
39 public:
40  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
41 
47 
48  typedef Eigen::Matrix<SCALAR, STATE_DIM, STATE_DIM + CONTROL_DIM> sensitivities_matrix_t;
49 
50 
58  const std::shared_ptr<ct::core::LinearSystem<STATE_DIM, CONTROL_DIM, SCALAR>>& linearSystem,
59  const std::shared_ptr<ct::core::Controller<STATE_DIM, CONTROL_DIM, SCALAR>>& controller,
61  bool timeVarying = true)
62  : timeVarying_(timeVarying), symplectic_(false), dt_(dt), substep_(0), k_(0), controller_(controller)
63  {
64  setLinearSystem(linearSystem);
65  setStepper(stepperType);
66  initStepper();
67  }
68 
69 
73  ~SensitivityIntegrator() override = default;
79  void setStepper(const ct::core::IntegrationType stepperType)
80  {
81  symplectic_ = false;
82 
83  switch (stepperType)
84  {
88  {
89  stepper_ = std::shared_ptr<ct::core::internal::StepperCTBase<sensitivities_matrix_t, SCALAR>>(
91  break;
92  }
93 
96  {
97  stepper_ = std::shared_ptr<ct::core::internal::StepperCTBase<sensitivities_matrix_t, SCALAR>>(
99  break;
100  }
101 
102  default:
103  throw std::runtime_error("Integration type not supported by sensitivity integrator");
104  }
105 
106  if (stepperType == ct::core::IntegrationType::EULER_SYM)
107  symplectic_ = true;
108  }
109 
117  virtual void setLinearSystem(
118  const std::shared_ptr<ct::core::LinearSystem<STATE_DIM, CONTROL_DIM, SCALAR>>& linearSystem) override
119  {
120  linearSystem_ = linearSystem;
121  }
122 
124  virtual void setTimeDiscretization(const SCALAR& dt) override { dt_ = dt; }
134  void integrateSensitivity(const size_t k, const size_t numSteps, state_matrix_t& A, state_control_matrix_t& B)
135  {
136  A.setIdentity();
137  B.setZero();
138 
139  sensitivities_matrix_t AB;
140  AB << A, B;
141 
142  k_ = k;
143  substep_ = 0;
144 
145  for (size_t i = 0; i < numSteps; ++i)
146  {
147  stepper_->do_step(dFdxDot_, AB, k * dt_, dt_);
148  }
149 
150  A = AB.template leftCols<STATE_DIM>();
151  B = AB.template rightCols<CONTROL_DIM>();
152  }
153 
165  const StateVector<STATE_DIM, SCALAR>& x_next,
166  const int n,
167  const size_t numSteps,
168  state_matrix_t& A,
169  state_control_matrix_t& B) override
170  {
171 #ifdef DEBUG
172  if (!(this->xSubstep_) || !(this->uSubstep_))
173  throw std::runtime_error("SensitivityIntegrator.h: Cached trajectories not set.");
174  if (this->xSubstep_->size() <= n || this->uSubstep_->size() <= n)
175  {
176  std::cout << "length x: " << this->xSubstep_->size() << std::endl;
177  std::cout << "length u: " << this->uSubstep_->size() << std::endl;
178  std::cout << "n: " << n << std::endl;
179  throw std::runtime_error("SensitivityIntegrator.h: Cached trajectories too short.");
180  }
181  if (!this->xSubstep_->at(n))
182  throw std::runtime_error("no state substeps available for requested time index");
183  if (!this->uSubstep_->at(n))
184  throw std::runtime_error("no control substeps available for requested time index");
185 
186  if (this->xSubstep_->at(n)->size() == 0)
187  throw std::runtime_error("substep state trajectory length for given time index is zero");
188  if (this->uSubstep_->at(n)->size() == 0)
189  throw std::runtime_error("substep control trajectory length for given time index is zero");
190 
191  assert(x == this->xSubstep_->operator[](n)->operator[](0) && "cached trajectory does not match provided state");
192  assert(u == this->uSubstep_->operator[](n)->operator[](0) && "cached trajectory does not match provided input");
193 #endif
194 
195  x_next_ = x_next;
196 
197  if (!timeVarying_)
198  {
199  Aconst_ = linearSystem_->getDerivativeState(x, u, n * dt_);
200  Bconst_ = linearSystem_->getDerivativeControl(x, u, n * dt_);
201  }
202 
203  integrateSensitivity(n, numSteps, A, B);
204  };
205 
206 
207 private:
208  bool timeVarying_;
209  bool symplectic_;
210  double dt_;
211  size_t substep_;
212  size_t k_;
213 
214  state_vector_t x_next_;
215 
216  state_matrix_t Aconst_;
217  state_control_matrix_t Bconst_;
218 
219  std::shared_ptr<ct::core::LinearSystem<STATE_DIM, CONTROL_DIM, SCALAR>> linearSystem_;
220  std::shared_ptr<ct::core::Controller<STATE_DIM, CONTROL_DIM, SCALAR>> controller_;
221 
222  // Sensitivities
223  std::function<void(const sensitivities_matrix_t&, sensitivities_matrix_t&, const SCALAR)> dFdxDot_;
224 
225  std::shared_ptr<ct::core::internal::StepperCTBase<sensitivities_matrix_t, SCALAR>> stepper_;
226 
227 
228  inline void integrateSensitivities(const state_matrix_t& A,
229  const state_control_matrix_t& B,
230  const state_vector_t& x,
231  const sensitivities_matrix_t& dX0In,
232  sensitivities_matrix_t& dX0dt,
233  const SCALAR t)
234  {
235  dX0dt.template leftCols<STATE_DIM>() = A * dX0In.template leftCols<STATE_DIM>();
236  dX0dt.template rightCols<CONTROL_DIM>() =
237  A * dX0In.template rightCols<CONTROL_DIM>() + B * controller_->getDerivativeU0(x, t);
238  }
239 
240  void initStepper()
241  {
242  dFdxDot_ = [this](const sensitivities_matrix_t& dX0In, sensitivities_matrix_t& dX0dt, const SCALAR t) {
243 #ifdef DEBUG
244  if (!this->xSubstep_ || this->xSubstep_->size() <= this->k_)
245  throw std::runtime_error("substeps not correctly initialized");
246 #endif
247 
249  this->xSubstep_->operator[](this->k_);
251  this->uSubstep_->operator[](this->k_);
252 
253 #ifdef DEBUG
254 
255  if (!xSubstep || xSubstep->size() <= this->substep_)
256  {
257  throw std::runtime_error("substeps not correctly initialized");
258  }
259 #endif
260  const state_vector_t& x = xSubstep->operator[](this->substep_);
261  const control_vector_t& u = uSubstep->operator[](this->substep_);
262 
263  if (symplectic_)
264  {
265  state_matrix_t A_sym;
266  state_control_matrix_t B_sym;
267  const state_vector_t* x_next;
268 
269  if (this->substep_ + 1 < xSubstep->size())
270  x_next = &xSubstep->operator[](this->substep_ + 1);
271  else
272  x_next = &x_next_;
273 
274  getSymplecticAandB<V_DIM, P_DIM>(t, x, *x_next, u, A_sym, B_sym);
275 
276  integrateSensitivities(A_sym, B_sym, x, dX0In, dX0dt, t);
277  }
278  else
279  {
280  if (timeVarying_)
281  {
282  state_matrix_t A = linearSystem_->getDerivativeState(x, u, t);
283  state_control_matrix_t B = linearSystem_->getDerivativeControl(x, u, t);
284 
285  integrateSensitivities(A, B, x, dX0In, dX0dt, t);
286  }
287  else
288  {
289  integrateSensitivities(Aconst_, Bconst_, x, dX0In, dX0dt, t);
290  }
291  }
292 
293  this->substep_++;
294  };
295  }
296 
297  SYMPLECTIC_ENABLED getSymplecticAandB(const SCALAR& t,
298  const state_vector_t& x,
299  const state_vector_t& x_next,
300  const control_vector_t& u,
301  state_matrix_t& A_sym,
302  state_control_matrix_t& B_sym)
303  {
304  // our implementation of symplectic integrators first updates the positions, we need to reconstruct an intermediate state accordingly
305  state_vector_t x_interm = x;
306  x_interm.template topRows<P_DIM>() = x_next.template topRows<P_DIM>();
307 
308  state_matrix_t Ac1 =
309  linearSystem_->getDerivativeState(x, u, t); // continuous time A matrix for start state and control
310  state_control_matrix_t Bc1 =
311  linearSystem_->getDerivativeControl(x, u, t); // continuous time B matrix for start state and control
312  state_matrix_t Ac2 = linearSystem_->getDerivativeState(
313  x_interm, u, t); // continuous time A matrix for intermediate state and control
314  state_control_matrix_t Bc2 = linearSystem_->getDerivativeControl(
315  x_interm, u, t); // continuous time B matrix for intermediate state and control
316 
317 
318  typedef Eigen::Matrix<SCALAR, P_DIM, P_DIM> p_matrix_t;
319  typedef Eigen::Matrix<SCALAR, V_DIM, V_DIM> v_matrix_t;
320  typedef Eigen::Matrix<SCALAR, P_DIM, V_DIM> p_v_matrix_t;
321  typedef Eigen::Matrix<SCALAR, V_DIM, P_DIM> v_p_matrix_t;
322  typedef Eigen::Matrix<SCALAR, P_DIM, CONTROL_DIM> p_control_matrix_t;
323  typedef Eigen::Matrix<SCALAR, V_DIM, CONTROL_DIM> v_control_matrix_t;
324 
325  // for ease of notation, make a block-wise map to references
326  // elements taken form the linearization at the starting state
327  const Eigen::Ref<const p_matrix_t> A11 = Ac1.template topLeftCorner<P_DIM, P_DIM>();
328  const Eigen::Ref<const p_v_matrix_t> A12 = Ac1.template topRightCorner<P_DIM, V_DIM>();
329  const Eigen::Ref<const p_control_matrix_t> B1 = Bc1.template topRows<P_DIM>();
330 
331  // elements taken from the linearization at the intermediate state
332  const Eigen::Ref<const v_p_matrix_t> A21 = Ac2.template bottomLeftCorner<V_DIM, P_DIM>();
333  const Eigen::Ref<const v_matrix_t> A22 = Ac2.template bottomRightCorner<V_DIM, V_DIM>();
334  const Eigen::Ref<const v_control_matrix_t> B2 = Bc2.template bottomRows<V_DIM>();
335 
336  // discrete approximation A matrix
337  A_sym.template topLeftCorner<P_DIM, P_DIM>() = A11;
338  A_sym.template topRightCorner<P_DIM, V_DIM>() = A12;
339  A_sym.template bottomLeftCorner<V_DIM, P_DIM>() = (A21 * (p_matrix_t::Identity() + dt_ * A11));
340  A_sym.template bottomRightCorner<V_DIM, V_DIM>() = (A22 + dt_ * A21 * A12);
341 
342  // discrete approximation B matrix
343  B_sym.template topRows<P_DIM>() = B1;
344  B_sym.template bottomRows<V_DIM>() = (B2 + dt_ * A21 * B1);
345  }
346 
347  SYMPLECTIC_DISABLED getSymplecticAandB(const SCALAR& t,
348  const state_vector_t& x,
349  const state_vector_t& x_next,
350  const control_vector_t& u,
351  state_matrix_t& A_sym,
352  state_control_matrix_t& B_sym)
353  {
354  throw std::runtime_error("Cannot compute sensitivities for symplectic system with these dimensions.");
355  }
356 };
357 }
358 }
359 
360 
361 #undef SYMPLECTIC_ENABLED
362 #undef SYMPLECTIC_DISABLED
interface class for a general linear system or linearized system
Definition: LinearSystem.h:23
std::shared_ptr< ControlVectorArray< CONTROL_DIM, SCALAR > > ControlVectorArrayPtr
Definition: Sensitivity.h:39
void setStepper(const ct::core::IntegrationType stepperType)
Initializes the steppers.
Definition: SensitivityIntegrator.h:79
std::vector< ControlVectorArrayPtr, Eigen::aligned_allocator< ControlVectorArrayPtr > > * uSubstep_
Definition: Sensitivity.h:88
StateMatrix< STATE_DIM, SCALAR > state_matrix_t
state Jacobian type
Definition: SensitivityIntegrator.h:44
Definition: Integrator.h:32
virtual void setTimeDiscretization(const SCALAR &dt) override
update the time discretization
Definition: SensitivityIntegrator.h:124
ct::core::ControlVector< control_dim > u
Custom implementation of the euler stepper.
Definition: SteppersCT.h:81
Eigen::Matrix< SCALAR, STATE_DIM, STATE_DIM+CONTROL_DIM > sensitivities_matrix_t
Definition: SensitivityIntegrator.h:48
#define SYMPLECTIC_ENABLED
Definition: SensitivityIntegrator.h:12
Definition: StateMatrix.h:12
virtual void setLinearSystem(const std::shared_ptr< ct::core::LinearSystem< STATE_DIM, CONTROL_DIM, SCALAR >> &linearSystem) override
Prepares the integrator to provide first order sensitivity generation by setting a linearsystem...
Definition: SensitivityIntegrator.h:117
clear all close all load ct GNMSLog0 mat reformat t
StateControlMatrix< STATE_DIM, CONTROL_DIM, SCALAR > state_control_matrix_t
input Jacobian type
Definition: SensitivityIntegrator.h:46
Definition: ControlVector.h:12
#define SYMPLECTIC_DISABLED
Definition: SensitivityIntegrator.h:15
CppAD::AD< CppAD::cg::CG< double > > SCALAR
SensitivityIntegrator(const SCALAR dt, const std::shared_ptr< ct::core::LinearSystem< STATE_DIM, CONTROL_DIM, SCALAR >> &linearSystem, const std::shared_ptr< ct::core::Controller< STATE_DIM, CONTROL_DIM, SCALAR >> &controller, const ct::core::IntegrationType stepperType=ct::core::IntegrationType::EULERCT, bool timeVarying=true)
Constructor.
Definition: SensitivityIntegrator.h:57
constexpr size_t n
Definition: MatrixInversionTest.cpp:14
Definition: StateVector.h:12
for i
Definition: Integrator.h:33
Definition: Integrator.h:39
virtual void getAandB(const StateVector< STATE_DIM, SCALAR > &x, const ControlVector< CONTROL_DIM, SCALAR > &u, const StateVector< STATE_DIM, SCALAR > &x_next, const int n, const size_t numSteps, state_matrix_t &A, state_control_matrix_t &B) override
Definition: SensitivityIntegrator.h:163
ct::core::StateVector< state_dim > x
Definition: Sensitivity.h:33
void integrateSensitivity(const size_t k, const size_t numSteps, state_matrix_t &A, state_control_matrix_t &B)
Integrates the sensitivity ODE of the integrator with respect to the initial state x0...
Definition: SensitivityIntegrator.h:134
Definition: Integrator.h:41
ControlMatrix< CONTROL_DIM, SCALAR > control_matrix_t
state Jacobian type
Definition: SensitivityIntegrator.h:45
ct::core::ControlVector< CONTROL_DIM, SCALAR > control_vector_t
Definition: SensitivityIntegrator.h:43
EIGEN_MAKE_ALIGNED_OPERATOR_NEW typedef ct::core::StateVector< STATE_DIM, SCALAR > state_vector_t
Definition: SensitivityIntegrator.h:42
This class can integrate a controlled system Furthermore, it provides first order derivatives with re...
Definition: SensitivityIntegrator.h:37
std::vector< StateVectorArrayPtr, Eigen::aligned_allocator< StateVectorArrayPtr > > * xSubstep_
Definition: Sensitivity.h:87
Custom implementation of the rk4 integration scheme.
Definition: SteppersCT.h:107
Definition: Integrator.h:40
~SensitivityIntegrator() override=default
Destroys the object.
Definition: ControlMatrix.h:12
Definition: StateControlMatrix.h:12
Interface class for all controllers.
Definition: Controller.h:26
IntegrationType
The available integration types.
Definition: Integrator.h:30