humoto
control_problem.h
Go to the documentation of this file.
1 /**
2  @file
3  @author Alexander Sherikov
4  @author Don Joven Agravante
5  @copyright 2014-2017 INRIA, 2014-2015 CNRS. Licensed under the Apache
6  License, Version 2.0. (see @ref LICENSE or http://www.apache.org/licenses/LICENSE-2.0)
7 
8  @brief
9 */
10 
11 #pragma once
12 
13 namespace humoto
14 {
15  /**
16  * @brief Status of control problem
17  */
19  {
20  public:
21  enum Status
22  {
23  /// Not initialized
24  UNDEFINED = 0,
25  /// Working
26  OK = 1,
27  /// Control terminated
28  STOPPED = 2
29  };
30  };
31 
32 
33 
34  /**
35  * @brief Abstract base class (for control problems)
36  *
37  * To be extended to represent each particular problem, i.e. walking pattern
38  * generator or whole body controller.
39  */
41  {
42  protected:
44 
45 
46  protected:
47  /**
48  * @brief Protected destructor: prevent destruction of the child
49  * classes through a base pointer.
50  */
53 
54 
55  public:
56  /**
57  * @brief Initialize structure of the given solution based on the
58  * internally stored solution structure.
59  *
60  * @param[out] solution solution
61  *
62  * @attention This method is called automatically.
63  */
65  {
66  HUMOTO_ASSERT(sol_structure_.isNonEmpty(),
67  "Structure of the solution in ControlProblem class is not properly initialized.");
68  solution.initialize(sol_structure_);
69  }
70 
71 
72 
73  /**
74  * @brief Guess solution
75  *
76  * @param[out] solution_guess solution guess
77  * @param[in] old_solution old solution
78  *
79  * @attention This method is called automatically. Can (and often
80  * should) be redefined in derived classes.
81  */
82  virtual void guessSolution( Solution &solution_guess,
83  const Solution &old_solution) const
84  {
85  solution_guess.initialize(sol_structure_, old_solution);
86  }
87 
88 
89  virtual void log( humoto::Logger &, const LogEntryName &, const std::string &) const = 0;
90  };
91 
92 
93 
94  /**
95  * @brief Abstract base class for Model Predictive Control problems.
96  */
98  {
99  protected:
100  /**
101  * @brief Protected destructor: prevent destruction of the child
102  * classes through a base pointer.
103  */
104  ~MPC() {}
105  MPC() {}
106 
107 
108  /**
109  * @brief Condense output of the system.
110  *
111  * output = Ox*x0 + Ou*(u0,...,uN)
112  *
113  * @tparam t_num_vars number of state variables
114  * @tparam t_num_outputs number of output variables
115  * @tparam t_DMatrix D matrix, should be an Eigen matrix or a scalar
116  * @tparam t_EMatrix E matrix, should be an Eigen matrix or a scalar
117  *
118  * @param[out] Ox matrix Ox
119  * @param[out] Ou vector of Ou matrices
120  * @param[in] D vector of D matrices
121  * @param[in] E vector of E matrices
122  * @param[in] Ux matrix Ux
123  * @param[in] Uu vector of Uu matrices
124  */
125  template<int t_num_vars,
126  int t_num_outputs,
127  typename t_DMatrix,
128  typename t_EMatrix>
129  static void condenseOutput(
131  std::vector< etools::LeftLowerTriangularBlockMatrix<t_num_outputs,
133  const std::vector<t_DMatrix> &D,
134  const std::vector<t_EMatrix> &E,
136  const std::vector< etools::LeftLowerTriangularBlockMatrix< t_num_vars,
138  {
139  std::ptrdiff_t N = Ux.getNumberOfBlocksVertical();
140 
142  "Wrong size of Ux matrix.")
143  HUMOTO_ASSERT(D.size() == E.size(), "Mismatching number of D and E matrices.")
144  HUMOTO_ASSERT(E.size() == static_cast<std::size_t>(N), "Wrong number of matrices.")
145 
146 
147  std::ptrdiff_t num_controls = 0;
148  std::vector<std::ptrdiff_t> control_offsets;
149 
150 
151  Ox.resize(N, 1);
152  Ox(0, 0) = D[0];
153 
154  Ou.resize(Uu.size());
155  control_offsets.resize(Uu.size());
156  for (std::size_t i = 0; i < Uu.size(); ++i)
157  {
158  control_offsets[i] = num_controls;
159  num_controls += Uu[i].getBlockColsNum();
160  Ou[i].setBlockSize(etools::MatrixBlockSizeType::UNDEFINED, Uu[i].getBlockColsNum());
161  Ou[i].setZero(N, N);
162  }
163 
164  for (std::size_t i = 0; i < Uu.size(); ++i)
165  {
166  Ou[i](N-1, N-1) = E[0].block( 0,
167  control_offsets[i],
168  t_num_outputs,
169  Uu[i].getBlockColsNum());
170  }
171 
172  for (std::ptrdiff_t i = 1; i < N; ++i)
173  {
174  Ox(i, 0).noalias() = D[i] * Ux(i-1, 0);
175 
176  for (std::size_t j = 0; j < Uu.size(); ++j)
177  {
178  Ou[j].row(i, 0, i).noalias() = D[i] * Uu[j].row(i-1, 0, i);
179  Ou[j](i, i) = E[i].block( 0,
180  control_offsets[j],
181  t_num_outputs,
182  Uu[j].getBlockColsNum());
183  }
184  }
185  }
186 
187 
188 
189  /**
190  * @brief Condense output of the system.
191  *
192  * output = Ox*x0 + Ou*(u0,...,uN)
193  *
194  * @tparam t_num_vars number of state variables
195  * @tparam t_num_controls number of control variables
196  * @tparam t_num_outputs number of output variables
197  * @tparam t_DMatrix D matrix, should be an Eigen matrix or a scalar
198  * @tparam t_EMatrix E matrix, should be an Eigen matrix or a scalar
199  *
200  * @param[out] Ox matrix Ox
201  * @param[out] Ou matrix Ou
202  * @param[in] D D matrix
203  * @param[in] E E matrix
204  * @param[in] Ux matrix Ux
205  * @param[in] Uu matrix Uu
206  */
207  template<typename t_DMatrix,
208  typename t_EMatrix>
209  static void condenseOutput(
210  Eigen::MatrixXd &Ox,
211  Eigen::MatrixXd &Ou,
212  const t_DMatrix &D,
213  const t_EMatrix &E,
214  const Eigen::MatrixXd &Ux,
215  const Eigen::MatrixXd &Uu)
216  {
217  size_t Nu = E.cols();
218  size_t Nx = D.cols();
219  size_t Ny = D.rows();
220  size_t N = Ux.rows()/Nx;
221  HUMOTO_ASSERT(Ux.cols() == (long)Nx,
222  "Mismatching sizes between Ux and D matrix.")
223  HUMOTO_ASSERT(Ux.rows() == (long)N*(long)Nx,
224  "Mismatching sizes between Ux and D matrix.")
225  HUMOTO_ASSERT(Uu.cols() == (long)N*(long)Nu,
226  "Mismatching sizes between Uu and E matrix.")
227  HUMOTO_ASSERT(Uu.rows() == (long)N*(long)Nx,
228  "Mismatching sizes between Uu and E matrix.")
229 
230  Ox.resize(N*Ny, Nx);
231  Ox.block(0, 0, Ny, Nx) = D;
232 
233  Ou.setZero(N*Ny, N*Nu);
234  Ou.block(0, 0, Ny, Nu) = E;
235 
236  for (size_t i = 1; i < N; ++i)
237  {
238  Ox.block(i*Ny, 0, Ny, Nx).noalias() =
239  D * Ux.block((i-1)*Nx, 0, Nx, Nx);
240 
241  Ou.middleRows(i*Ny, Ny).noalias() = D * Uu.middleRows((i-1)*Nx, Nx);
242  Ou.block(i*Ny, i*Nu, Ny, Nu) = E;
243  }
244  }
245  /**
246  * @brief Condense output of the system.
247  *
248  * output = Ox*x0 + Ou*(u0,...,uN)
249  *
250  * @tparam t_num_vars number of state variables
251  * @tparam t_num_controls number of control variables
252  * @tparam t_num_outputs number of output variables
253  * @tparam t_DMatrix D matrix, should be an Eigen matrix or a scalar
254  * @tparam t_EMatrix E matrix, should be an Eigen matrix or a scalar
255  *
256  * @param[out] Ox matrix Ox
257  * @param[out] Ou matrix Ou
258  * @param[in] D vector of D matrices
259  * @param[in] E vector of E matrices
260  * @param[in] Ux matrix Ux
261  * @param[in] Uu matrix Uu
262  */
263  template<int t_num_vars,
264  int t_num_controls,
265  int t_num_outputs,
266  typename t_DMatrix,
267  typename t_EMatrix>
268  static void condenseOutput(
271  const std::vector<t_DMatrix> &D,
272  const std::vector<t_EMatrix> &E,
275  {
276  std::ptrdiff_t N = Ux.getNumberOfBlocksVertical();
277 
279  "Wrong size of Ux matrix.")
281  && (Uu.getNumberOfBlocksVertical() == N),
282  "Mismatching size of input matrices.")
283  HUMOTO_ASSERT(D.size() == E.size(), "Mismatching number of D and E matrices.")
284  HUMOTO_ASSERT(E.size() == static_cast<std::size_t>(N), "Wrong number of matrices.")
285 
286 
287  Ox.resize(N, 1);
288  Ox(0, 0) = D[0];
289 
290  Ou.setZero(N, N);
291  Ou(0, 0) = E[0];
292 
293  for (std::ptrdiff_t i = 1; i < N; ++i)
294  {
295  Ox(i, 0).noalias() = D[i] * Ux(i-1, 0);
296 
297  Ou.row(i, 0, i).noalias() = D[i] * Uu.row(i-1, 0, i);
298  Ou(i, i) = E[i];
299  }
300  }
301 
302 
303  /**
304  * @brief Create the condensed matrices (S,U) of a Model Predictive Control problem such that X = S*x0 + U*u
305  *
306  * @tparam t_num_vars number of variables
307  * @tparam t_num_controls number of controls
308  * @tparam t_AMatrix A matrix, should be an Eigen matrix or a scalar
309  * @tparam t_BMatrix B matrix, should be an Eigen matrix
310  *
311  * @param[out] S
312  * @param[out] U
313  * @param[in] A
314  * @param[in] B
315  */
316  template<int t_num_vars,
317  int t_num_controls,
318  typename t_AMatrix,
319  typename t_BMatrix,
320  etools::MatrixSparsityType::Type t_bmatrix_sparsity_type>
321  static void condense(
324  const std::vector<t_AMatrix> &A,
325  const std::vector<t_BMatrix> &B)
326  {
327  HUMOTO_ASSERT(A.size() == B.size(), "Mismatching number of A and B matrices.")
328  HUMOTO_ASSERT(A.size() > 0, "Wrong number of matrices.")
329 
330  std::ptrdiff_t N = A.size();
331 
332  S.resize(N, 1);
333  U.setZero(N, N);
334 
335  // form U (right to left)
336  // S is partially formed in the process
337  S(N-1, 0).setIdentity();
338  // last column
339  U(N-1, N-1) = B[N-1];
340  // other columns
341  for(std::ptrdiff_t k=N-2; k>=0; --k)
342  {
343  //S.column(0, k+1, N-k-1) *= A[k+1];
344  //loop is faster for blocks with constant size
345  for (std::ptrdiff_t i = k+1; i < N; ++i)
346  {
347  S(i, 0) *= A[k+1];
348  }
349  S(k, 0).setIdentity();
350 
351  U(k, k) = B[k];
352  //U.column(k, k+1, N-k-1).noalias() = S.column(0, k+1, N-k-1) * B[k];
353  //loop is faster for blocks with constant size
354  for (std::ptrdiff_t i = k+1; i < N; ++i)
355  {
356  U(i, k).noalias() = S(i, 0) * B[k];
357  }
358  }
359 
360 
361  // finalize formulation of S
362  S.column(0) *= A[0];
363  }
364 
365 
366  /**
367  * @brief Create the condensed matrices (S,U) of a Model Predictive Control problem such that X = S*x0 + U*u
368  *
369  * @tparam t_AMatrix A matrix, should be an Eigen matrix or a scalar
370  * @tparam t_BMatrix B matrix, should be an Eigen matrix
371  *
372  * @param[out] S
373  * @param[out] U
374  * @param[in] A
375  * @param[in] B
376  */
377  template<typename t_AMatrix, typename t_BMatrix>
378  static void condense(
379  Eigen::MatrixXd &S,
380  Eigen::MatrixXd &U,
381  const std::vector<t_AMatrix> &A,
382  const std::vector<t_BMatrix> &B)
383  {
384  HUMOTO_ASSERT(A.size() == B.size(), "Mismatching number of A and B matrices.")
385  HUMOTO_ASSERT(A.size() > 0, "Wrong number of matrices.")
386  HUMOTO_ASSERT((A[0].rows() == B[0].rows()) && (A[0].cols() == B[0].rows()), "Wrong size of matrices.");
387 
388  int N = A.size();
389  int Ns = B[0].rows();
390  int Nu = B[0].cols();
391 
392 
393  S.resize(Ns * N, Ns);
394  U.resize(Ns*N, Nu*N);
395 
396  // form U (right to left)
397  // S is partially formed in the process
398  U.setZero();
399  S.block((N-1)*Ns, 0, Ns, Ns).setIdentity();
400  // last column
401  U.block((N-1)*Ns, (N-1)*Nu, Ns, Nu) = B[N-1];
402  // other columns
403  for(int k=N-2; k>=0; --k)
404  {
405  S.block((k+1)*Ns, 0, (N-k-1)*Ns, Ns) *= A[k+1];
406  S.block(k*Ns, 0, Ns, Ns).setIdentity();
407 
408  U.block((k)*Ns, k*Nu, Ns, Nu) = B[k];
409  U.block((k+1)*Ns, k*Nu, (N-k-1)*Ns, Nu).noalias() = S.block((k+1)*Ns, 0, (N-k-1)*Ns, Ns) * B[k];
410  }
411 
412 
413  // finalize formulation of S
414  S *= A[0];
415  }
416 
417 
418  /**
419  * @brief Create the condensed matrices (S,U) of a Time Invariant (constant A,B)
420  * Model Predictive Control problem such that X = S*x0 + U*u
421  *
422  * @param[out] S
423  * @param[out] U
424  * @param[in] preview_horizon_len length of the preview horizon
425  * @param[in] A
426  * @param[in] B
427  */
429  Eigen::MatrixXd &S,
430  Eigen::MatrixXd &U,
431  const std::size_t preview_horizon_len,
432  const Eigen::MatrixXd &A,
433  const Eigen::MatrixXd &B)
434  {
435  // form S
436  Eigen::MatrixXd M = A;
437  int num_rows_A = A.rows();
438  int num_cols_A = A.cols();
439  S.resize(num_rows_A*preview_horizon_len, num_cols_A);
440  S.block(0, 0 , num_rows_A, num_cols_A) = M;
441 
442  for(std::size_t i=1; i<preview_horizon_len; ++i)
443  {
444  M = M * A;
445  S.block(i*num_rows_A, 0 , num_rows_A, num_cols_A) = M;
446  }
447 
448  // form U
449  int num_rows_B = B.rows();
450  int num_cols_B = B.cols();
451  Eigen::MatrixXd Ucol(num_rows_B*preview_horizon_len, num_cols_B);
452  Ucol << B,
453  S.block(0, 0 , num_rows_B*(preview_horizon_len-1), num_cols_A) * B;
454  U.resize(num_rows_B*preview_horizon_len, num_cols_B*preview_horizon_len);
455  U.setZero();
456  for(std::size_t i=0; i<preview_horizon_len; ++i)
457  {
458  U.block(num_rows_B*i, num_cols_B*i, num_rows_B*(preview_horizon_len-i), num_cols_B) = Ucol.block(0, 0, num_rows_B*(preview_horizon_len-i), num_cols_B);
459  }
460  }
461  };
462 }
Abstract base class (for control problems)
A shorthand class for a specific sparsity type.
Definition: blockmatrix.h:270
Status of control problem.
static void condenseOutput(etools::GenericBlockMatrix< t_num_outputs, t_num_vars > &Ox, etools::LeftLowerTriangularBlockMatrix< t_num_outputs, t_num_controls > &Ou, const std::vector< t_DMatrix > &D, const std::vector< t_EMatrix > &E, const etools::GenericBlockMatrix< t_num_vars, t_num_vars > &Ux, const etools::LeftLowerTriangularBlockMatrix< t_num_vars, t_num_controls > &Uu)
Condense output of the system.
#define HUMOTO_LOCAL
Definition: export_import.h:26
Block matrix, the raw matrix is stored inside (not a reference).
Definition: blockmatrix.h:178
#define HUMOTO_ASSERT(condition, message)
~MPC()
Protected destructor: prevent destruction of the child classes through a base pointer.
Analog of &#39;sol_structure&#39; struct in Octave code. [determine_solution_structure.m].
Definition: solution.h:33
void setZero(const std::ptrdiff_t num_blocks_vert, const std::ptrdiff_t num_blocks_hor)
Resize matrix and initialize it with zeros.
Container of the solution.
Definition: solution.h:176
Represents log entry name.
Definition: logger.h:169
static void condense(etools::GenericBlockMatrix< t_num_vars, t_num_vars > &S, etools::BlockMatrix< t_num_vars, t_num_controls, t_bmatrix_sparsity_type > &U, const std::vector< t_AMatrix > &A, const std::vector< t_BMatrix > &B)
Create the condensed matrices (S,U) of a Model Predictive Control problem such that X = S*x0 + U*u...
bool isNonEmpty() const
Checks if the structure is empty or not.
Definition: solution.h:88
A shorthand class for a specific sparsity type.
Definition: blockmatrix.h:266
virtual void guessSolution(Solution &solution_guess, const Solution &old_solution) const
Guess solution.
void resize(const std::ptrdiff_t num_blocks_vert, const std::ptrdiff_t num_blocks_hor)
Resize matrix.
void initSolutionStructure(humoto::Solution &solution) const
Initialize structure of the given solution based on the internally stored solution structure...
~ControlProblem()
Protected destructor: prevent destruction of the child classes through a base pointer.
static void condense(Eigen::MatrixXd &S, Eigen::MatrixXd &U, const std::vector< t_AMatrix > &A, const std::vector< t_BMatrix > &B)
Create the condensed matrices (S,U) of a Model Predictive Control problem such that X = S*x0 + U*u...
Threaded logger: any data sent to this logger is wrapped in a message and pushed to a queue...
Definition: logger.h:555
void initialize(const SolutionStructure &sol_structure)
Initialize the solution vector.
Definition: solution.h:214
DynamicMatrixBlock column(const std::ptrdiff_t index_col, const std::ptrdiff_t index_row_first, const std::ptrdiff_t index_num_rows)
Access column of a matrix.
SolutionStructure sol_structure_
static void condenseOutput(Eigen::MatrixXd &Ox, Eigen::MatrixXd &Ou, const t_DMatrix &D, const t_EMatrix &E, const Eigen::MatrixXd &Ux, const Eigen::MatrixXd &Uu)
Condense output of the system.
std::ptrdiff_t getNumberOfBlocksHorizontal() const
Get number of blocks (horizontal/vertical)
The root namespace of HuMoTo.
Definition: config.h:12
DynamicMatrixBlock row(const std::ptrdiff_t index_row, const std::ptrdiff_t index_col_first, const std::ptrdiff_t index_num_cols)
Access row of a matrix.
static void condenseOutput(etools::GenericBlockMatrix< t_num_outputs, t_num_vars > &Ox, std::vector< etools::LeftLowerTriangularBlockMatrix< t_num_outputs, etools::MatrixBlockSizeType::DYNAMIC > > &Ou, const std::vector< t_DMatrix > &D, const std::vector< t_EMatrix > &E, const etools::GenericBlockMatrix< t_num_vars, t_num_vars > &Ux, const std::vector< etools::LeftLowerTriangularBlockMatrix< t_num_vars, etools::MatrixBlockSizeType::DYNAMIC > > &Uu)
Condense output of the system.
std::ptrdiff_t getNumberOfBlocksVertical() const
Get number of blocks (horizontal/vertical)
static void condenseTimeInvariant(Eigen::MatrixXd &S, Eigen::MatrixXd &U, const std::size_t preview_horizon_len, const Eigen::MatrixXd &A, const Eigen::MatrixXd &B)
Create the condensed matrices (S,U) of a Time Invariant (constant A,B) Model Predictive Control probl...
Abstract base class for Model Predictive Control problems.