GenQPUtils.h
Go to the documentation of this file.
1 /*
2  * Copyright 2012-2019 CNRS-UM LIRMM, CNRS-AIST JRL
3  */
4 
5 #pragma once
6 
7 // includes
8 // std
9 #include <vector>
10 
11 // Eigen
12 #include <Eigen/Core>
13 #include <Eigen/Sparse>
14 
15 // Tasks
16 #include "Tasks/QPSolver.h"
17 
18 namespace tasks
19 {
20 
21 namespace qp
22 {
23 
24 // Value add to the diagonal to ensure positive matrix
25 static const double DIAG_CONSTANT = 1e-4;
26 
31 inline void fillQC(const std::vector<Task *> & tasks, int nrVars, Eigen::MatrixXd & Q, Eigen::VectorXd & C)
32 {
33  for(std::size_t i = 0; i < tasks.size(); ++i)
34  {
35  const Eigen::MatrixXd & Qi = tasks[i]->Q();
36  const Eigen::VectorXd & Ci = tasks[i]->C();
37  std::pair<int, int> b = tasks[i]->begin();
38 
39  int r = static_cast<int>(Qi.rows());
40  int c = static_cast<int>(Qi.cols());
41 
42  Q.block(b.first, b.second, r, c) += tasks[i]->weight() * Qi;
43  C.segment(b.first, r) += tasks[i]->weight() * Ci;
44  }
45 
46  // try to transform Q_ to a positive matrix
47  // we just add a small value to the diagonal since
48  // the first necessary condition is to have
49  // Q_(i,i) > 0
50  // may be we can try to check the second
51  // condition in a near futur
52  // Q_(i,i) + Q_(j,j) > 2·Q_(i,j) for i≠j
53  for(int i = 0; i < nrVars; ++i)
54  {
55  if(std::abs(Q(i, i)) < DIAG_CONSTANT) { Q(i, i) += DIAG_CONSTANT; }
56  }
57 }
58 
78 inline void reduceQC(const Eigen::MatrixXd & QFull,
79  const Eigen::VectorXd & CFull,
80  Eigen::MatrixXd & Q,
81  Eigen::VectorXd & C,
82  const Eigen::SparseMatrix<double> & M)
83 {
84  Q.noalias() = M.transpose() * QFull * M;
85  C.noalias() = M.transpose() * CFull;
86 }
87 
88 // general qp form
89 
94 inline int fillEq(const std::vector<Equality *> & eq,
95  int nrVars,
96  int nrALines,
97  Eigen::MatrixXd & A,
98  Eigen::VectorXd & AL,
99  Eigen::VectorXd & AU)
100 {
101  for(std::size_t i = 0; i < eq.size(); ++i)
102  {
103  // ineq constraint can return a matrix with more line
104  // than the number of constraint
105  int nrConstr = eq[i]->nrEq();
106  const Eigen::MatrixXd & Ai = eq[i]->AEq();
107  const Eigen::VectorXd & bi = eq[i]->bEq();
108 
109  A.block(nrALines, 0, nrConstr, nrVars) = Ai.block(0, 0, nrConstr, nrVars);
110  AL.segment(nrALines, nrConstr) = bi.head(nrConstr);
111  AU.segment(nrALines, nrConstr) = bi.head(nrConstr);
112 
113  nrALines += nrConstr;
114  }
115 
116  return nrALines;
117 }
118 
123 inline int fillInEq(const std::vector<Inequality *> & inEq,
124  int nrVars,
125  int nrALines,
126  Eigen::MatrixXd & A,
127  Eigen::VectorXd & AL,
128  Eigen::VectorXd & AU)
129 {
130  for(std::size_t i = 0; i < inEq.size(); ++i)
131  {
132  // ineq constraint can return a matrix with more line
133  // than the number of constraint
134  int nrConstr = inEq[i]->nrInEq();
135  const Eigen::MatrixXd & Ai = inEq[i]->AInEq();
136  const Eigen::VectorXd & bi = inEq[i]->bInEq();
137 
138  A.block(nrALines, 0, nrConstr, nrVars) = Ai.block(0, 0, nrConstr, nrVars);
139  AL.segment(nrALines, nrConstr).fill(-std::numeric_limits<double>::infinity());
140  AU.segment(nrALines, nrConstr) = bi.head(nrConstr);
141 
142  nrALines += nrConstr;
143  }
144 
145  return nrALines;
146 }
147 
152 inline int fillGenInEq(const std::vector<GenInequality *> & genInEq,
153  int nrVars,
154  int nrALines,
155  Eigen::MatrixXd & A,
156  Eigen::VectorXd & AL,
157  Eigen::VectorXd & AU)
158 {
159  for(std::size_t i = 0; i < genInEq.size(); ++i)
160  {
161  // ineq constraint can return a matrix with more line
162  // than the number of constraint
163  int nrConstr = genInEq[i]->nrGenInEq();
164  const Eigen::MatrixXd & Ai = genInEq[i]->AGenInEq();
165  const Eigen::VectorXd & ALi = genInEq[i]->LowerGenInEq();
166  const Eigen::VectorXd & AUi = genInEq[i]->UpperGenInEq();
167 
168  A.block(nrALines, 0, nrConstr, nrVars) = Ai.block(0, 0, nrConstr, nrVars);
169  AL.segment(nrALines, nrConstr) = ALi.head(nrConstr);
170  AU.segment(nrALines, nrConstr) = AUi.head(nrConstr);
171 
172  nrALines += nrConstr;
173  }
174 
175  return nrALines;
176 }
177 
178 // standard qp form
179 
184 inline int fillEq(const std::vector<Equality *> & eq, int nrVars, int nrALines, Eigen::MatrixXd & A, Eigen::VectorXd & b)
185 {
186  for(std::size_t i = 0; i < eq.size(); ++i)
187  {
188  // ineq constraint can return a matrix with more line
189  // than the number of constraint
190  int nrConstr = eq[i]->nrEq();
191  const Eigen::MatrixXd & Ai = eq[i]->AEq();
192  const Eigen::VectorXd & bi = eq[i]->bEq();
193 
194  A.block(nrALines, 0, nrConstr, nrVars) = Ai.block(0, 0, nrConstr, nrVars);
195  b.segment(nrALines, nrConstr) = bi.head(nrConstr);
196 
197  nrALines += nrConstr;
198  }
199 
200  return nrALines;
201 }
202 
207 inline int fillInEq(const std::vector<Inequality *> & inEq,
208  int nrVars,
209  int nrALines,
210  Eigen::MatrixXd & A,
211  Eigen::VectorXd & b)
212 {
213  for(std::size_t i = 0; i < inEq.size(); ++i)
214  {
215  // ineq constraint can return a matrix with more line
216  // than the number of constraint
217  int nrConstr = inEq[i]->nrInEq();
218  const Eigen::MatrixXd & Ai = inEq[i]->AInEq();
219  const Eigen::VectorXd & bi = inEq[i]->bInEq();
220 
221  A.block(nrALines, 0, nrConstr, nrVars) = Ai.block(0, 0, nrConstr, nrVars);
222  b.segment(nrALines, nrConstr) = bi.head(nrConstr);
223 
224  nrALines += nrConstr;
225  }
226 
227  return nrALines;
228 }
229 
234 inline int fillGenInEq(const std::vector<GenInequality *> & genInEq,
235  int nrVars,
236  int nrALines,
237  Eigen::MatrixXd & A,
238  Eigen::VectorXd & b)
239 {
240  for(std::size_t i = 0; i < genInEq.size(); ++i)
241  {
242  // ineq constraint can return a matrix with more line
243  // than the number of constraint
244  int nrConstr = genInEq[i]->nrGenInEq();
245  const Eigen::MatrixXd & Ai = genInEq[i]->AGenInEq();
246  const Eigen::VectorXd & ALi = genInEq[i]->LowerGenInEq();
247  const Eigen::VectorXd & AUi = genInEq[i]->UpperGenInEq();
248 
249  A.block(nrALines, 0, nrConstr, nrVars) = -Ai.block(0, 0, nrConstr, nrVars);
250  b.segment(nrALines, nrConstr) = -ALi.head(nrConstr);
251 
252  nrALines += nrConstr;
253 
254  A.block(nrALines, 0, nrConstr, nrVars) = Ai.block(0, 0, nrConstr, nrVars);
255  b.segment(nrALines, nrConstr) = AUi.head(nrConstr);
256 
257  nrALines += nrConstr;
258  }
259 
260  return nrALines;
261 }
262 
267 inline void fillBound(const std::vector<Bound *> & bounds, Eigen::VectorXd & XL, Eigen::VectorXd & XU)
268 {
269  for(std::size_t i = 0; i < bounds.size(); ++i)
270  {
271  const Eigen::VectorXd & XLi = bounds[i]->Lower();
272  const Eigen::VectorXd & XUi = bounds[i]->Upper();
273  int bv = bounds[i]->beginVar();
274 
275  XL.segment(bv, XLi.size()) = XLi;
276  XU.segment(bv, XUi.size()) = XUi;
277  }
278 }
279 
297 inline void reduceA(const Eigen::MatrixXd & AFull, Eigen::MatrixXd & A, const Eigen::SparseMatrix<double> & M)
298 {
299  A.noalias() = AFull * M;
300 }
301 
305 inline void reduceBound(const Eigen::VectorXd & XLFull,
306  Eigen::VectorXd & XL,
307  const Eigen::VectorXd & XUFull,
308  Eigen::VectorXd & XU,
309  const std::vector<int> & fullToReduced,
310  const std::vector<int> & reducedToFull,
311  const std::vector<std::tuple<int, int, double>> & dependencies)
312 {
313  for(size_t i = 0; i < static_cast<size_t>(XL.rows()); ++i)
314  {
315  XL(static_cast<Eigen::DenseIndex>(i)) = XLFull(reducedToFull[i]);
316  XU(static_cast<Eigen::DenseIndex>(i)) = XUFull(reducedToFull[i]);
317  }
318  for(const auto & d : dependencies)
319  {
320  const int & primaryFullI = std::get<0>(d);
321  const int & primaryReducedI = fullToReduced[static_cast<size_t>(primaryFullI)];
322  const int & replicaFullI = std::get<1>(d);
323  const double & alpha = std::get<2>(d);
324  if(alpha != 0)
325  {
327  if(alpha < 0)
328  {
329  XL(primaryReducedI) = std::max(XL(primaryReducedI), XUFull(replicaFullI) / alpha);
330  XU(primaryReducedI) = std::min(XU(primaryReducedI), XLFull(replicaFullI) / alpha);
331  }
332  else
333  {
334  XL(primaryReducedI) = std::max(XL(primaryReducedI), XLFull(replicaFullI) / alpha);
335  XU(primaryReducedI) = std::min(XU(primaryReducedI), XUFull(replicaFullI) / alpha);
336  }
337  }
338  }
339 }
340 
344 inline void expandResult(const Eigen::VectorXd & result,
345  Eigen::VectorXd & resultFull,
346  const Eigen::SparseMatrix<double> & multipliers)
347 {
348  resultFull.noalias() = multipliers * result;
349 }
350 
351 // print of a constraint at a given line
352 template<typename T>
353 std::ostream & printConstr(const Eigen::VectorXd & result, T * constr, int line, std::ostream & out);
354 
355 template<>
356 inline std::ostream & printConstr(const Eigen::VectorXd & result, Equality * constr, int line, std::ostream & out)
357 {
358  out << constr->AEq().row(line) * result << " = " << constr->bEq()(line);
359  return out;
360 }
361 
362 template<>
363 inline std::ostream & printConstr(const Eigen::VectorXd & result, Inequality * constr, int line, std::ostream & out)
364 {
365  out << constr->AInEq().row(line) * result << " <= " << constr->bInEq()(line);
366  return out;
367 }
368 
369 template<>
370 inline std::ostream & printConstr(const Eigen::VectorXd & result, GenInequality * constr, int line, std::ostream & out)
371 {
372  out << constr->LowerGenInEq()(line) << " <= " << constr->AGenInEq().row(line) * result
373  << " <= " << constr->UpperGenInEq()(line);
374  return out;
375 }
376 
377 template<typename T>
378 inline std::ostream & constrErrorMsg(const std::vector<rbd::MultiBody> & mbs,
379  const Eigen::VectorXd & result,
380  int ALine,
381  const std::vector<T *> & constr,
382  int & start,
383  int & end,
384  std::ostream & out)
385 {
386  for(T * e : constr)
387  {
388  end += constr_traits<T>::nrLines(e);
389  if(ALine >= start && ALine < end)
390  {
391  int line = ALine - start;
392  out << constr_traits<T>::name(e) << " violated at line: " << line << std::endl;
393  out << constr_traits<T>::desc(e, mbs, line) << std::endl;
394  printConstr(result, e, line, out) << std::endl;
395  start = end;
396  break;
397  }
398  start = end;
399  }
400  return out;
401 }
402 
403 } // namespace qp
404 
405 } // namespace tasks
tasks::qp::expandResult
void expandResult(const Eigen::VectorXd &result, Eigen::VectorXd &resultFull, const Eigen::SparseMatrix< double > &multipliers)
Definition: GenQPUtils.h:344
tasks::qp::reduceBound
void reduceBound(const Eigen::VectorXd &XLFull, Eigen::VectorXd &XL, const Eigen::VectorXd &XUFull, Eigen::VectorXd &XU, const std::vector< int > &fullToReduced, const std::vector< int > &reducedToFull, const std::vector< std::tuple< int, int, double >> &dependencies)
Definition: GenQPUtils.h:305
tasks::qp::Equality::AEq
virtual const Eigen::MatrixXd & AEq() const =0
tasks::qp::reduceA
void reduceA(const Eigen::MatrixXd &AFull, Eigen::MatrixXd &A, const Eigen::SparseMatrix< double > &M)
Definition: GenQPUtils.h:297
tasks::qp::Inequality
Definition: QPSolver.h:224
tasks::qp::GenInequality::LowerGenInEq
virtual const Eigen::VectorXd & LowerGenInEq() const =0
tasks::qp::fillGenInEq
int fillGenInEq(const std::vector< GenInequality * > &genInEq, int nrVars, int nrALines, Eigen::MatrixXd &A, Eigen::VectorXd &AL, Eigen::VectorXd &AU)
Definition: GenQPUtils.h:152
tasks::qp::Inequality::AInEq
virtual const Eigen::MatrixXd & AInEq() const =0
tasks::qp::Inequality::bInEq
virtual const Eigen::VectorXd & bInEq() const =0
tasks::qp::constrErrorMsg
std::ostream & constrErrorMsg(const std::vector< rbd::MultiBody > &mbs, const Eigen::VectorXd &result, int ALine, const std::vector< T * > &constr, int &start, int &end, std::ostream &out)
Definition: GenQPUtils.h:378
tasks::qp::reduceQC
void reduceQC(const Eigen::MatrixXd &QFull, const Eigen::VectorXd &CFull, Eigen::MatrixXd &Q, Eigen::VectorXd &C, const Eigen::SparseMatrix< double > &M)
Definition: GenQPUtils.h:78
tasks::qp::fillBound
void fillBound(const std::vector< Bound * > &bounds, Eigen::VectorXd &XL, Eigen::VectorXd &XU)
Definition: GenQPUtils.h:267
tasks::qp::Equality::bEq
virtual const Eigen::VectorXd & bEq() const =0
tasks::qp::fillQC
void fillQC(const std::vector< Task * > &tasks, int nrVars, Eigen::MatrixXd &Q, Eigen::VectorXd &C)
Definition: GenQPUtils.h:31
tasks::qp::Equality
Definition: QPSolver.h:206
tasks::qp::GenInequality::AGenInEq
virtual const Eigen::MatrixXd & AGenInEq() const =0
tasks::qp::constr_traits
Definition: QPSolver.h:320
tasks::qp::fillInEq
int fillInEq(const std::vector< Inequality * > &inEq, int nrVars, int nrALines, Eigen::MatrixXd &A, Eigen::VectorXd &AL, Eigen::VectorXd &AU)
Definition: GenQPUtils.h:123
tasks::qp::printConstr
std::ostream & printConstr(const Eigen::VectorXd &result, T *constr, int line, std::ostream &out)
tasks::qp::fillEq
int fillEq(const std::vector< Equality * > &eq, int nrVars, int nrALines, Eigen::MatrixXd &A, Eigen::VectorXd &AL, Eigen::VectorXd &AU)
Definition: GenQPUtils.h:94
tasks::qp::GenInequality
Definition: QPSolver.h:242
tasks
Definition: GenQPUtils.h:18
tasks::qp::GenInequality::UpperGenInEq
virtual const Eigen::VectorXd & UpperGenInEq() const =0
QPSolver.h