quadratic_cost.cpp
Go to the documentation of this file.
1 /*********************************************************************
2  *
3  * Software License Agreement
4  *
5  * Copyright (c) 2020,
6  * TU Dortmund - Institute of Control Theory and Systems Engineering.
7  * All rights reserved.
8  *
9  * This program is free software: you can redistribute it and/or modify
10  * it under the terms of the GNU General Public License as published by
11  * the Free Software Foundation, either version 3 of the License, or
12  * (at your option) any later version.
13  *
14  * This program is distributed in the hope that it will be useful,
15  * but WITHOUT ANY WARRANTY; without even the implied warranty of
16  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17  * GNU General Public License for more details.
18  *
19  * You should have received a copy of the GNU General Public License
20  * along with this program. If not, see <https://www.gnu.org/licenses/>.
21  *
22  * Authors: Christoph Rösmann
23  *********************************************************************/
24 
26 
28 
29 #include <cmath>
30 
31 namespace corbo {
32 
34 {
36 
37  if (!is_square(Q)) return false;
38 
39  // check if we have a diagonal matrix
40  if (Q.isDiagonal(1e-10)) return setWeightQ(Q.diagonal().asDiagonal());
41 
42  _Q_diagonal_mode = false;
44 
45  _Q = Q; // also store original matrix
46  if (Q.isZero())
47  {
48  _Q_sqrt.setZero();
49  return true;
50  }
52  if (cholesky.info() == Eigen::NumericalIssue) return false;
53  _Q_sqrt = cholesky.matrixU();
54  return true;
55 }
56 
58 {
60  _Q_diagonal_mode = true;
61  _Q_diag = Q;
62  _Q_diag_sqrt = Q.diagonal().cwiseSqrt().asDiagonal();
63  _Q = Q.toDenseMatrix();
64  return true;
65 }
66 
68 {
70 
71  if (!is_square(R)) return false;
72 
73  // check if we have a diagonal matrix
74  if (R.isDiagonal(1e-10)) return setWeightR(R.diagonal().asDiagonal());
75 
76  _R_diagonal_mode = false;
77 
78  _R = R; // also store original matrix
79  if (R.isZero())
80  {
81  _R_sqrt.setZero();
82  return true;
83  }
85  if (cholesky.info() == Eigen::NumericalIssue) return false;
86  _R_sqrt = cholesky.matrixU();
87  return true;
88 }
89 
91 {
93  _R_diagonal_mode = true;
94  _R_diag = R;
95  _R_diag_sqrt = R.diagonal().cwiseSqrt().asDiagonal();
96  _R = R.toDenseMatrix();
97  return true;
98 }
99 
101 {
102  assert(!_integral_form);
103  assert(cost.size() == getNonIntegralStateTermDimension(k));
104 
105  if (_lsq_form)
106  {
107  if (_zero_x_ref)
108  {
109  if (_Q_diagonal_mode)
110  cost.noalias() = _Q_diag_sqrt * x_k;
111  else
112  cost.noalias() = x_k.transpose() * _Q_sqrt * x_k;
113  }
114  else
115  {
116  Eigen::VectorXd xd = x_k - _x_ref->getReferenceCached(k);
117  if (_Q_diagonal_mode)
118  cost.noalias() = _Q_diag_sqrt * xd;
119  else
120  cost.noalias() = _Q_sqrt * xd;
121  }
122  }
123  else
124  {
125  if (_zero_x_ref)
126  {
127  if (_Q_diagonal_mode)
128  cost.noalias() = x_k.transpose() * _Q_diag * x_k;
129  else
130  cost.noalias() = x_k.transpose() * _Q * x_k;
131  }
132  else
133  {
134  Eigen::VectorXd xd = x_k - _x_ref->getReferenceCached(k);
135  if (_Q_diagonal_mode)
136  cost.noalias() = xd.transpose() * _Q_diag * xd;
137  else
138  cost.noalias() = xd.transpose() * _Q * xd;
139  }
140  }
141 }
142 
144 {
145  assert(!_integral_form);
146  assert(cost.size() == getNonIntegralControlTermDimension(k));
147 
148  if (_lsq_form)
149  {
150  if (_zero_u_ref)
151  {
152  if (_R_diagonal_mode)
153  cost.noalias() = _R_diag_sqrt * u_k;
154  else
155  cost.noalias() = _R_sqrt * u_k;
156  }
157  else
158  {
159  Eigen::VectorXd ud = u_k - _u_ref->getReferenceCached(k);
160  if (_R_diagonal_mode)
161  cost.noalias() = ud.transpose() * _R_diag_sqrt * ud;
162  else
163  cost.noalias() = ud.transpose() * _R_sqrt * ud;
164  }
165  }
166  else
167  {
168  if (_zero_u_ref)
169  {
170  if (_R_diagonal_mode)
171  cost.noalias() = u_k.transpose() * _R_diag * u_k;
172  else
173  cost.noalias() = u_k.transpose() * _R * u_k;
174  }
175  else
176  {
177  Eigen::VectorXd ud = u_k - _u_ref->getReferenceCached(k);
178  if (_R_diagonal_mode)
179  cost.noalias() = ud.transpose() * _R_diag * ud;
180  else
181  cost.noalias() = ud.transpose() * _R * ud;
182  }
183  }
184 }
185 
188 {
189  assert(_integral_form);
190  assert(cost.size() == 1);
191 
192  cost[0] = 0;
193 
194  if (_zero_x_ref)
195  {
196  if (_Q_diagonal_mode)
197  cost[0] += x_k.transpose() * _Q_diag * x_k;
198  else
199  cost[0] += x_k.transpose() * _Q * x_k;
200  }
201  else
202  {
203  Eigen::VectorXd xd = x_k - _x_ref->getReferenceCached(k);
204  if (_Q_diagonal_mode)
205  cost[0] += xd.transpose() * _Q_diag * xd;
206  else
207  cost[0] += xd.transpose() * _Q * xd;
208  }
209  if (_zero_u_ref)
210  {
211  if (_R_diagonal_mode)
212  cost[0] += u_k.transpose() * _R_diag * u_k;
213  else
214  cost[0] += u_k.transpose() * _R * u_k;
215  }
216  else
217  {
218  Eigen::VectorXd ud = u_k - _u_ref->getReferenceCached(k);
219  if (_R_diagonal_mode)
220  cost[0] += ud.transpose() * _R_diag * ud;
221  else
222  cost[0] += ud.transpose() * _R * ud;
223  }
224 }
225 
226 bool QuadraticFormCost::checkParameters(int state_dim, int control_dim, std::stringstream* issues) const
227 {
228  bool success = true;
229 
231  {
232  if (_Q_diag.diagonal().size() != state_dim)
233  {
234  if (issues)
235  *issues << "QuadraticFormCost: Diagonal matrix dimension of Q (" << _Q_diag.diagonal().size()
236  << ") does not match state vector dimension (" << state_dim << "); Please specify diagonal elements only." << std::endl;
237  success = false;
238  }
239  }
240  else
241  {
242  if (_Q.rows() != state_dim || _Q.cols() != state_dim)
243  {
244  if (issues)
245  *issues << "QuadraticFormCost: Matrix dimension of Q (" << _Q.rows() << "x" << _Q.cols()
246  << ") does not match state vector dimension (" << state_dim << "); Please specify " << (state_dim * state_dim)
247  << " elements (Row-Major)." << std::endl;
248  success = false;
249  }
250  }
251 
253  {
254  if (_R_diag.diagonal().size() != control_dim)
255  {
256  if (issues)
257  *issues << "QuadraticFormCost: diagonal matrix dimension of R (" << _R_diag.diagonal().size()
258  << ") does not match control input vector dimension (" << control_dim << "); Please specify diagonal elements only."
259  << std::endl;
260  success = false;
261  }
262  }
263  else
264  {
265  if (_R.rows() != control_dim || _R.cols() != control_dim)
266  {
267  if (issues)
268  *issues << "QuadraticFormCost: Matrix dimension of R (" << _R.rows() << "x" << _R.cols()
269  << ") does not match control input vector dimension (" << control_dim << "); Please specify " << (control_dim * control_dim)
270  << " elements (Row-Major)." << std::endl;
271  success = false;
272  }
273  }
274 
275  return success;
276 }
277 
279 {
280  _Q *= scale;
281  _Q_diag.diagonal() *= scale;
282  _Q_sqrt *= scale;
283  _Q_diag_sqrt.diagonal() *= scale;
284 }
285 
287 {
288  _R *= scale;
289  _R_diag.diagonal() *= scale;
290  _R_sqrt *= scale;
291  _R_diag_sqrt.diagonal() *= scale;
292 }
293 
294 #ifdef MESSAGE_SUPPORT
295 bool QuadraticFormCost::fromMessage(const messages::QuadraticFormCost& message, std::stringstream* issues)
296 {
297  const messages::QuadraticFormCost& msg = message;
298 
299  _Q_diagonal_mode = msg.q_diagonal_only();
300  _R_diagonal_mode = msg.r_diagonal_only();
301 
302  // Weight matrix Q
303  if (_Q_diagonal_mode)
304  {
305  if (!setWeightQ(Eigen::Map<const Eigen::Matrix<double, -1, 1>>(msg.q().data(), msg.q_size()).asDiagonal()))
306  {
307  *issues << "QuadraticStateCost: cannot set diagonal weight matrix Q.\n";
308  return false;
309  }
310  }
311  else
312  {
313  int p = std::sqrt(msg.q_size());
314 
315  if (p * p != msg.q_size())
316  {
317  *issues << "QuadraticStateCost: weight matrix Q is not square.\n";
318  return false;
319  }
320 
321  // weight matrix Q
322  // if (p * p == message.full_discretization_ocp().q_size())
323  //{
324  if (!setWeightQ(Eigen::Map<const Eigen::Matrix<double, -1, -1, Eigen::RowMajor>>(msg.q().data(), p, p)) && issues)
325  {
326  *issues << "QuadraticStateCost: weight matrix Q is not positive definite.\n";
327  return false;
328  }
329  //}
330  // else if (issues)
331  // *issues << "QuadraticStateCost: invalid size of weight matrix Q: it shout be [" << p << " x " << p << "].\n";
332  }
333 
334  // Weight matrix R
335  if (_R_diagonal_mode)
336  {
337  if (!setWeightR(Eigen::Map<const Eigen::Matrix<double, -1, 1>>(msg.r().data(), msg.r_size()).asDiagonal()))
338  {
339  *issues << "QuadraticFormCost: cannot set diagonal weight matrix R.\n";
340  return false;
341  }
342  }
343  else
344  {
345  double q = std::sqrt(msg.r_size());
346 
347  if (q * q != msg.r_size())
348  {
349  *issues << "QuadraticFormCost: weight matrix R is not square.\n";
350  return false;
351  }
352 
353  // weight matrix Q
354  // if (p * p == message.full_discretization_ocp().q_size())
355  //{
356  if (!setWeightR(Eigen::Map<const Eigen::Matrix<double, -1, -1, Eigen::RowMajor>>(msg.r().data(), q, q)) && issues)
357  {
358  *issues << "QuadraticFormCost: weight matrix R is not positive definite.\n";
359  return false;
360  }
361  //}
362  // else if (issues)
363  // *issues << "QuadraticControlCost: invalid size of weight matrix Q: it shout be [" << p << " x " << p << "].\n";
364  }
365 
366  // others
367  _lsq_form = msg.lsq_form();
368  _integral_form = msg.integral_form();
369 
370  return true;
371 }
372 
373 void QuadraticFormCost::toMessage(messages::QuadraticFormCost& message) const
374 {
375  messages::QuadraticFormCost* msg = &message;
376 
377  // weight matrix Q
379  {
380  Eigen::VectorXd Qdiag = _Q_diag.diagonal();
381  msg->mutable_q()->Resize(Qdiag.size(), 0);
382  Eigen::Map<Eigen::VectorXd>(msg->mutable_q()->mutable_data(), Qdiag.size()) = Qdiag;
383 
384  msg->set_q_diagonal_only(true);
385  }
386  else
387  {
388  Eigen::MatrixXd Q = _Q; // Q = _Q_sqrt.adjoint() * _Q_sqrt;
389  msg->mutable_q()->Resize(Q.rows() * Q.cols(), 0);
390  Eigen::Map<Eigen::Matrix<double, -1, -1, Eigen::RowMajor>>(msg->mutable_q()->mutable_data(), Q.rows(), Q.cols()) = Q;
391 
392  msg->set_q_diagonal_only(false);
393  }
394 
395  // weight matrix R
397  {
398  Eigen::VectorXd Rdiag = _R_diag.diagonal();
399  msg->mutable_r()->Resize(Rdiag.size(), 0);
400  Eigen::Map<Eigen::VectorXd>(msg->mutable_r()->mutable_data(), Rdiag.size()) = Rdiag;
401 
402  msg->set_r_diagonal_only(true);
403  }
404  else
405  {
406  Eigen::MatrixXd R = _R; // R = _R_sqrt.adjoint() * _R_sqrt;
407  msg->mutable_r()->Resize(R.rows() * R.cols(), 0);
408  Eigen::Map<Eigen::Matrix<double, -1, -1, Eigen::RowMajor>>(msg->mutable_r()->mutable_data(), R.rows(), R.cols()) = R;
409 
410  msg->set_r_diagonal_only(false);
411  }
412 
413  // others
414  msg->set_lsq_form(_lsq_form);
415  msg->set_integral_form(_integral_form);
416 }
417 #endif
418 
419 } // namespace corbo
Eigen::DiagonalMatrix< double, -1 > _Q_diag_sqrt
void computeNonIntegralControlTerm(int k, const Eigen::Ref< const Eigen::VectorXd > &u_k, Eigen::Ref< Eigen::VectorXd > cost) const override
EIGEN_DEVICE_FUNC const DiagonalVectorType & diagonal() const
A matrix or vector expression mapping an existing array of data.
Definition: Map.h:94
EIGEN_DEVICE_FUNC const SqrtReturnType sqrt() const
Eigen::DiagonalMatrix< double, -1 > _R_diag_sqrt
bool setWeightR(const Eigen::Ref< const Eigen::MatrixXd > &R)
const ReferenceTrajectoryInterface * _x_ref
int getNonIntegralControlTermDimension(int k) const override
bool is_square(const Eigen::MatrixBase< Derived > &matrix)
Determine if a given matrix is square.
void computeIntegralStateControlTerm(int k, const Eigen::Ref< const Eigen::VectorXd > &x_k, const Eigen::Ref< const Eigen::VectorXd > &u_k, Eigen::Ref< Eigen::VectorXd > cost) const override
void computeNonIntegralStateTerm(int k, const Eigen::Ref< const Eigen::VectorXd > &x_k, Eigen::Ref< Eigen::VectorXd > cost) const override
virtual const OutputVector & getReferenceCached(int k) const =0
Eigen::DiagonalMatrix< double, -1 > _Q_diag
Standard Cholesky decomposition (LL^T) of a matrix and associated features.
Definition: LLT.h:56
EIGEN_DEVICE_FUNC const Scalar & q
bool checkParameters(int state_dim, int control_dim, std::stringstream *issues) const override
ComputationInfo info() const
Reports whether previous computation was successful.
Definition: LLT.h:186
A matrix or vector expression mapping an existing expression.
Definition: Ref.h:192
int getNonIntegralStateTermDimension(int k) const override
bool setWeightQ(const Eigen::Ref< const Eigen::MatrixXd > &Q)
Traits::MatrixU matrixU() const
Definition: LLT.h:119
Eigen::DiagonalMatrix< double, -1 > _R_diag
EIGEN_DEVICE_FUNC DenseMatrixType toDenseMatrix() const
const ReferenceTrajectoryInterface * _u_ref
The matrix class, also used for vectors and row-vectors.
Definition: Matrix.h:178
void scaleCurrentWeightQ(double scale)
void scaleCurrentWeightR(double scale)


control_box_rst
Author(s): Christoph Rösmann
autogenerated on Mon Feb 28 2022 22:07:14