- 3.0.2 optimal control module.
DiscreteConstraintContainerBase.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 
8 #include <memory>
9 #include <Eigen/Core>
11 
12 namespace ct {
13 namespace optcon {
14 namespace tpl {
15 
22 template <typename SCALAR>
24 {
25 public:
26  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
27 
28  using VectorXs = Eigen::Matrix<SCALAR, Eigen::Dynamic, 1>;
29  using VectorXi = Eigen::Matrix<int, Eigen::Dynamic, 1>;
30  using MapVecXs = Eigen::Map<VectorXs>;
31  using MapVecXi = Eigen::Map<VectorXi>;
32 
40  virtual ~DiscreteConstraintContainerBase() = default;
46  virtual void prepareEvaluation() = 0;
47 
53  virtual void prepareJacobianEvaluation() = 0;
54 
55 
63  {
65  size_t ind = 0;
66 
67  for (auto constraint : constraints_)
68  {
69  size_t cSize = constraint->getConstraintSize();
70  c_nlp.segment(ind, cSize) = constraint->eval();
71  ind += cSize;
72  }
73 
74  assert(ind == static_cast<size_t>(c_nlp.rows())); // or throw an error
75  }
76 
78  {
80  size_t ind = 0;
81 
82  for (auto constraint : constraints_)
83  {
84  size_t cSize = constraint->getConstraintSize();
85  c_nlp.segment(ind, cSize) = constraint->eval();
86  ind += cSize;
87  }
88 
89  assert(static_cast<int>(ind) == c_nlp.rows()); // or throw an error
90  }
91 
99  void evalSparseJacobian(MapVecXs& jac_nlp, const int nzz_jac_g)
100  {
102  size_t ind = 0;
103 
104  for (auto constraint : constraints_)
105  {
106  size_t nnEle = constraint->getNumNonZerosJacobian();
107  jac_nlp.segment(ind, nnEle) = constraint->evalSparseJacobian();
108  ind += nnEle;
109  }
110 
111  assert(static_cast<int>(ind) == nzz_jac_g);
112  }
113 
124  void getSparsityPattern(Eigen::Map<Eigen::VectorXi>& iRow_nlp,
125  Eigen::Map<Eigen::VectorXi>& jCol_nlp,
126  const int nnz_jac_g)
127  {
128  size_t ind = 0;
129  size_t constraintCount = 0;
130 
131  for (auto constraint : constraints_)
132  {
133  size_t nnEle = constraint->getNumNonZerosJacobian();
134  size_t cSize = constraint->getConstraintSize();
135  Eigen::VectorXi iRow, jCol;
136  iRow.resize(nnEle);
137  jCol.resize(nnEle);
138  constraint->genSparsityPattern(iRow, jCol);
139  iRow_nlp.segment(ind, nnEle) = iRow.array() + constraintCount;
140  jCol_nlp.segment(ind, nnEle) = jCol;
141  constraintCount += cSize;
142  ind += nnEle;
143  }
144 
145  assert(static_cast<int>(ind) == nnz_jac_g);
146  }
147 
153  size_t getConstraintsCount() const
154  {
155  size_t count = 0;
156  for (auto constraint : constraints_)
157  count += constraint->getConstraintSize();
158  return count;
159  }
160 
167  {
168  size_t count = 0;
169  for (auto constraint : constraints_)
170  count += constraint->getNumNonZerosJacobian();
171  return count;
172  }
173 
174 
180  void getSparsityPatternHessian(Eigen::VectorXi& iRow, Eigen::VectorXi& jCol, size_t numOptVar)
181  {
182 #if EIGEN_VERSION_AT_LEAST(3, 3, 0)
183 
184  // important initialization
185  constraintHessianTot_.resize(numOptVar, numOptVar);
186  constraintHessianSparsity_.resize(numOptVar, numOptVar);
187 
188  std::vector<Eigen::Triplet<SCALAR>, Eigen::aligned_allocator<Eigen::Triplet<SCALAR>>> triplets;
189 
190  for (size_t c = 0; c < constraints_.size(); c++)
191  {
192  // get sparsity pattern of every individual constraint term
193  constraints_[c]->genSparsityPatternHessian(constraints_[c]->iRowHessian(), constraints_[c]->jColHessian());
194  for (int i = 0; i < constraints_[c]->iRowHessian().rows(); i++)
195  triplets.push_back(Eigen::Triplet<SCALAR>(
196  constraints_[c]->iRowHessian()(i), constraints_[c]->jColHessian()(i), SCALAR(1.0)));
197  }
198 
199  // fill in values in total constraint Hessian
200  constraintHessianSparsity_.setFromTriplets(triplets.begin(), triplets.end());
201 
202 
203  iRowHessianStdVec_.clear();
204  jColHessianStdVec_.clear();
205  for (int k = 0; k < constraintHessianSparsity_.outerSize(); k++)
206  {
207  for (typename Eigen::SparseMatrix<SCALAR>::InnerIterator it(constraintHessianSparsity_, k); it; ++it)
208  {
209  iRowHessianStdVec_.push_back(it.row());
210  jColHessianStdVec_.push_back(it.col());
211  }
212  }
213 
214  iRow = Eigen::Map<Eigen::VectorXi>(iRowHessianStdVec_.data(), iRowHessianStdVec_.size(), 1);
215  jCol = Eigen::Map<Eigen::VectorXi>(jColHessianStdVec_.data(), jColHessianStdVec_.size(), 1);
216 #else
217  throw std::runtime_error(
218  "getSparsityPatternHessian only available for Eigen 3.3 and newer. Please change solver settings to NOT "
219  "use exact Hessians or upgrade Eigen version.");
220 #endif
221  }
222 
223 
231  Eigen::VectorXd sparseHessianValues(const Eigen::VectorXd& optVec, const Eigen::VectorXd& lambda)
232  {
233 #if EIGEN_VERSION_AT_LEAST(3, 3, 0)
234 
235  std::vector<Eigen::Triplet<SCALAR>, Eigen::aligned_allocator<Eigen::Triplet<SCALAR>>> triplets;
236 
237  size_t count = 0;
238  for (size_t c = 0; c < constraints_.size(); c++)
239  {
240  // count the constraint size to hand over correct portion of multiplier vector lambda
241  size_t c_nel = constraints_[c]->getConstraintSize();
242  Eigen::VectorXd hessianSubValues;
243  constraints_[c]->sparseHessianValues(optVec, lambda.segment(count, c_nel), hessianSubValues);
244  count += c_nel;
245 
246  // add the evaluated sub-hessian elements as triplets
247  for (int i = 0; i < hessianSubValues.rows(); i++)
248  triplets.push_back(Eigen::Triplet<SCALAR>(
249  constraints_[c]->iRowHessian()(i), constraints_[c]->jColHessian()(i), hessianSubValues(i)));
250  }
251 
252  // combine all triplets into the sparse constraint Hessian
253  constraintHessianTot_.setFromTriplets(triplets.begin(), triplets.end());
254 
255  // triangular-view required (todo: need better in-place assignment)
256  constraintHessianTot_ = constraintHessianTot_.template triangularView<Eigen::Lower>();
257 
258  size_t nele_constraint_hes = jColHessianStdVec_.size();
259  return Eigen::VectorXd(Eigen::Map<Eigen::VectorXd>(constraintHessianTot_.valuePtr(), nele_constraint_hes, 1));
260 #else
261  throw std::runtime_error(
262  "sparseHessianValues only available for Eigen 3.3 and newer. Please use BFGS Hessian approx or upgrade "
263  "Eigen version.");
264  return Eigen::VectorXd::Zero();
265 #endif
266  }
267 
275  void getBounds(MapVecXs& lowerBound, MapVecXs& upperBound)
276  {
277  size_t ind = 0;
278  for (auto constraint : constraints_)
279  {
280  size_t cSize = constraint->getConstraintSize();
281  lowerBound.segment(ind, cSize) = constraint->getLowerBound();
282  upperBound.segment(ind, cSize) = constraint->getUpperBound();
283  ind += cSize;
284  }
285  }
286 
287 protected:
289  std::vector<std::shared_ptr<DiscreteConstraintBase<SCALAR>>> constraints_;
290 
291  std::vector<int> iRowHessianStdVec_;
292  std::vector<int> jColHessianStdVec_;
293 
294 #if EIGEN_VERSION_AT_LEAST(3, 3, 0)
295  Eigen::SparseMatrix<SCALAR> constraintHessianTot_;
296  Eigen::SparseMatrix<SCALAR>
297  constraintHessianSparsity_; // helper to calculate sparsity and number of non-zero elements
298 #endif
299 };
300 
301 } // namespace tpl
302 
304 
305 } // namespace optcon
306 } // namespact ct
void getBounds(MapVecXs &lowerBound, MapVecXs &upperBound)
Retrieves the constraint bounds and writes them into the vectors used in the NLP. ...
Definition: DiscreteConstraintContainerBase.h:275
DiscreteConstraintContainerBase()=default
Default constructor.
void evalConstraints(MapVecXs &c_nlp)
Writes the constraint evaluations into the large constraint optimization vector.
Definition: DiscreteConstraintContainerBase.h:62
size_t getConstraintsCount() const
Returns the number of constraints in the NLP.
Definition: DiscreteConstraintContainerBase.h:153
virtual void prepareJacobianEvaluation()=0
Gets called before the constraint jacobian evaluation. This method should contain all the calculation...
virtual void prepareEvaluation()=0
Gets called before the constraint evaluation. This method should contain all the calculations needed ...
An abstract base class which serves as a container for all the discrete constraints used in the NLP...
Definition: DiscreteConstraintContainerBase.h:23
size_t getNonZerosJacobianCount() const
Returns the number of non zeros in the constraint jacobian.
Definition: DiscreteConstraintContainerBase.h:166
CppAD::AD< CppAD::cg::CG< double > > SCALAR
for i
Definition: mpc_unittest_plotting.m:14
void evalSparseJacobian(MapVecXs &jac_nlp, const int nzz_jac_g)
Evaluates the jacobian of the constraints and writes them into the nlp vector.
Definition: DiscreteConstraintContainerBase.h:99
void getSparsityPatternHessian(Eigen::VectorXi &iRow, Eigen::VectorXi &jCol, size_t numOptVar)
creates the combined hessian sparsity pattern from a number of constraint terms
Definition: DiscreteConstraintContainerBase.h:180
std::vector< int > iRowHessianStdVec_
Definition: DiscreteConstraintContainerBase.h:291
virtual ~DiscreteConstraintContainerBase()=default
Destructor.
std::vector< std::shared_ptr< DiscreteConstraintBase< SCALAR > > > constraints_
Container which holds all the constraints of the NLP.
Definition: DiscreteConstraintContainerBase.h:289
Eigen::VectorXd sparseHessianValues(const Eigen::VectorXd &optVec, const Eigen::VectorXd &lambda)
Evaluates the constraint Hessian.
Definition: DiscreteConstraintContainerBase.h:231
std::vector< int > jColHessianStdVec_
Definition: DiscreteConstraintContainerBase.h:292
void getSparsityPattern(Eigen::Map< Eigen::VectorXi > &iRow_nlp, Eigen::Map< Eigen::VectorXi > &jCol_nlp, const int nnz_jac_g)
Retrieves the sparsity pattern of the constraint Jacobian and writes them into the nlp vectors...
Definition: DiscreteConstraintContainerBase.h:124
Eigen::Matrix< int, Eigen::Dynamic, 1 > VectorXi
Definition: DiscreteConstraintContainerBase.h:29
Eigen::Map< VectorXs > MapVecXs
Definition: DiscreteConstraintContainerBase.h:30
void evalConstraints(VectorXs &c_nlp)
Definition: DiscreteConstraintContainerBase.h:77
Eigen::Map< VectorXi > MapVecXi
Definition: DiscreteConstraintContainerBase.h:31
Eigen::Matrix< SCALAR, Eigen::Dynamic, 1 > VectorXs
Definition: DiscreteConstraintContainerBase.h:28