tsid  1.8.0
Efficient Task Space Inverse Dynamics for Multi-body Systems based on Pinocchio
solver-HQP-eiquadprog-rt.hxx
Go to the documentation of this file.
1 //
2 // Copyright (c) 2017 CNRS
3 //
4 // This file is part of tsid
5 // tsid is free software: you can redistribute it
6 // and/or modify it under the terms of the GNU Lesser General Public
7 // License as published by the Free Software Foundation, either version
8 // 3 of the License, or (at your option) any later version.
9 // tsid is distributed in the hope that it will be
10 // useful, but WITHOUT ANY WARRANTY; without even the implied warranty
11 // of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
12 // General Lesser Public License for more details. You should have
13 // received a copy of the GNU Lesser General Public License along with
14 // tsid If not, see
15 // <http://www.gnu.org/licenses/>.
16 //
17 
18 #ifndef __invdyn_solvers_hqp_eiquadprog_rt_hxx__
19 #define __invdyn_solvers_hqp_eiquadprog_rt_hxx__
20 
22 #include "eiquadprog/eiquadprog-rt.hxx"
24 #include "tsid/math/utils.hpp"
25 
26 namespace eisol = eiquadprog::solvers;
27 
28 #define PROFILE_EIQUADPROG_PREPARATION "EiquadprogRT problem preparation"
29 #define PROFILE_EIQUADPROG_SOLUTION "EiquadprogRT problem solution"
30 
31 namespace tsid {
32 namespace solvers {
33 
34 template <int nVars, int nEqCon, int nIneqCon>
36  const std::string& name)
37  : SolverHQPBase(name),
38  m_hessian_regularization(DEFAULT_HESSIAN_REGULARIZATION) {
39  m_n = nVars;
40  m_neq = nEqCon;
41  m_nin = nIneqCon;
42  m_output.resize(nVars, nEqCon, 2 * nIneqCon);
43 }
44 
45 template <int nVars, int nEqCon, int nIneqCon>
47  std::cout << "[SolverHQuadProgRT." << m_name << "] " << s << std::endl;
48 }
49 
50 template <int nVars, int nEqCon, int nIneqCon>
52  unsigned int neq,
53  unsigned int nin) {
54  assert(n == nVars);
55  assert(neq == nEqCon);
56  assert(nin == nIneqCon);
57  if ((n != nVars) || (neq != nEqCon) || (nin != nIneqCon))
58  std::cerr
59  << "[SolverHQuadProgRT] (n!=nVars) || (neq!=nEqCon) || (nin!=nIneqCon)"
60  << std::endl;
61 }
62 
63 template <int nVars, int nEqCon, int nIneqCon>
65  const HQPData& problemData) {
66  using namespace tsid::math;
67 
68  // #ifndef EIGEN_RUNTIME_NO_MALLOC
69  // Eigen::internal::set_is_malloc_allowed(false);
70  // #endif
71 
72  START_PROFILER_EIQUADPROG_RT(PROFILE_EIQUADPROG_PREPARATION);
73 
74  if (problemData.size() > 2) {
75  PINOCCHIO_CHECK_INPUT_ARGUMENT(
76  false, "Solver not implemented for more than 2 hierarchical levels.");
77  }
78 
79  // Compute the constraint matrix sizes
80  unsigned int neq = 0, nin = 0;
81  const ConstraintLevel& cl0 = problemData[0];
82  if (cl0.size() > 0) {
83  const unsigned int n = cl0[0].second->cols();
84  for (ConstraintLevel::const_iterator it = cl0.begin(); it != cl0.end();
85  it++) {
86  auto constr = it->second;
87  assert(n == constr->cols());
88  if (constr->isEquality())
89  neq += constr->rows();
90  else
91  nin += constr->rows();
92  }
93  // If necessary, resize the constraint matrices
94  resize(n, neq, nin);
95 
96  int i_eq = 0, i_in = 0;
97  for (ConstraintLevel::const_iterator it = cl0.begin(); it != cl0.end();
98  it++) {
99  auto constr = it->second;
100  if (constr->isEquality()) {
101  m_CE.middleRows(i_eq, constr->rows()) = constr->matrix();
102  m_ce0.segment(i_eq, constr->rows()) = -constr->vector();
103  i_eq += constr->rows();
104  } else if (constr->isInequality()) {
105  m_CI.middleRows(i_in, constr->rows()) = constr->matrix();
106  m_ci0.segment(i_in, constr->rows()) = -constr->lowerBound();
107  i_in += constr->rows();
108  m_CI.middleRows(i_in, constr->rows()) = -constr->matrix();
109  m_ci0.segment(i_in, constr->rows()) = constr->upperBound();
110  i_in += constr->rows();
111  } else if (constr->isBound()) {
112  m_CI.middleRows(i_in, constr->rows()).setIdentity();
113  m_ci0.segment(i_in, constr->rows()) = -constr->lowerBound();
114  i_in += constr->rows();
115  m_CI.middleRows(i_in, constr->rows()) = -Matrix::Identity(m_n, m_n);
116  m_ci0.segment(i_in, constr->rows()) = constr->upperBound();
117  i_in += constr->rows();
118  }
119  }
120  } else
121  resize(m_n, neq, nin);
122 
123  if (problemData.size() > 1) {
124  const ConstraintLevel& cl1 = problemData[1];
125  m_H.setZero();
126  m_g.setZero();
127  for (ConstraintLevel::const_iterator it = cl1.begin(); it != cl1.end();
128  it++) {
129  const double& w = it->first;
130  auto constr = it->second;
131  if (!constr->isEquality())
132  PINOCCHIO_CHECK_INPUT_ARGUMENT(
133  false, "Inequalities in the cost function are not implemented yet");
134 
136  m_H.noalias() += w * constr->matrix().transpose() * constr->matrix();
138  m_g.noalias() -= w * (constr->matrix().transpose() * constr->vector());
139  }
140  m_H.diagonal().noalias() += m_hessian_regularization * Vector::Ones(m_n);
141  }
142 
143  STOP_PROFILER_EIQUADPROG_RT(PROFILE_EIQUADPROG_PREPARATION);
144 
145  // // eliminate equality constraints
146  // if(m_neq>0)
147  // {
148  // m_CE_lu.compute(m_CE);
149  // sendMsg("The rank of CD is "+toString(m_CE_lu.rank());
150  // const MatrixXd & Z = m_CE_lu.kernel();
151 
152  // }
153 
154  START_PROFILER_EIQUADPROG_RT(PROFILE_EIQUADPROG_SOLUTION);
155 
156  // min 0.5 * x G x + g0 x
157  // s.t.
158  // CE x + ce0 = 0
159  // CI x + ci0 >= 0
160  typename RtVectorX<nVars>::d sol(m_n);
162  eisol::RtEiquadprog_status status =
163  m_solver.solve_quadprog(m_H, m_g, m_CE, m_ce0, m_CI, m_ci0, sol);
164  STOP_PROFILER_EIQUADPROG_RT(PROFILE_EIQUADPROG_SOLUTION);
165 
166  m_output.x = sol;
167 
168  // #ifndef EIGEN_RUNTIME_NO_MALLOC
169  // Eigen::internal::set_is_malloc_allowed(true);
170  // #endif
171 
172  if (status == eisol::RT_EIQUADPROG_OPTIMAL) {
173  m_output.status = HQP_STATUS_OPTIMAL;
174  m_output.lambda = m_solver.getLagrangeMultipliers();
175  // m_output.activeSet = m_solver.getActiveSet().template tail< 2*nIneqCon
176  // >().head(m_solver.getActiveSetSize());
177  m_output.activeSet = m_solver.getActiveSet().segment(
178  m_neq, m_solver.getActiveSetSize() - m_neq);
179  m_output.iterations = m_solver.getIteratios();
180 
181 #ifndef NDEBUG
182  const Vector& x = m_output.x;
183 
184  if (cl0.size() > 0) {
185  for (ConstraintLevel::const_iterator it = cl0.begin(); it != cl0.end();
186  it++) {
187  auto constr = it->second;
188  if (constr->checkConstraint(x) == false) {
189  if (constr->isEquality()) {
190  sendMsg("Equality " + constr->name() + " violated: " +
191  toString((constr->matrix() * x - constr->vector()).norm()));
192  } else if (constr->isInequality()) {
193  sendMsg(
194  "Inequality " + constr->name() + " violated: " +
195  toString(
196  (constr->matrix() * x - constr->lowerBound()).minCoeff()) +
197  "\n" +
198  toString(
199  (constr->upperBound() - constr->matrix() * x).minCoeff()));
200  } else if (constr->isBound()) {
201  sendMsg("Bound " + constr->name() + " violated: " +
202  toString((x - constr->lowerBound()).minCoeff()) + "\n" +
203  toString((constr->upperBound() - x).minCoeff()));
204  }
205  }
206  }
207  }
208 #endif
209  } else if (status == eisol::RT_EIQUADPROG_UNBOUNDED)
210  m_output.status = HQP_STATUS_INFEASIBLE;
211  else if (status == eisol::RT_EIQUADPROG_MAX_ITER_REACHED)
212  m_output.status = HQP_STATUS_MAX_ITER_REACHED;
213  else if (status == eisol::RT_EIQUADPROG_REDUNDANT_EQUALITIES)
214  m_output.status = HQP_STATUS_ERROR;
215 
216  return m_output;
217 }
218 
219 template <int nVars, int nEqCon, int nIneqCon>
221  return m_solver.getObjValue();
222 }
223 
224 template <int nVars, int nEqCon, int nIneqCon>
226  unsigned int maxIter) {
228  return m_solver.setMaxIter(maxIter);
229 }
230 
231 } // namespace solvers
232 } // namespace tsid
233 
234 #endif // ifndef __invdyn_solvers_hqp_eiquadprog_rt_hxx__
Definition: solver-HQP-output.hpp:29
void resize(unsigned int nVars, unsigned int nEqCon, unsigned int nInCon)
Definition: solver-HQP-output.hpp:48
Abstract interface for a Quadratic Program (HQP) solver.
Definition: solver-HQP-base.hpp:34
virtual bool setMaximumIterations(unsigned int maxIter)
Definition: solver-HQP-base.cpp:36
HQPOutput m_output
Definition: solver-HQP-base.hpp:84
double getObjectiveValue() override
Definition: solver-HQP-eiquadprog-rt.hxx:220
int m_n
number of inequality constraints
Definition: solver-HQP-eiquadprog-rt.hpp:90
const HQPOutput & solve(const HQPData &problemData) override
Definition: solver-HQP-eiquadprog-rt.hxx:64
void sendMsg(const std::string &s)
Definition: solver-HQP-eiquadprog-rt.hxx:46
int m_nin
number of equality constraints
Definition: solver-HQP-eiquadprog-rt.hpp:89
void resize(unsigned int n, unsigned int neq, unsigned int nin) override
Definition: solver-HQP-eiquadprog-rt.hxx:51
bool setMaximumIterations(unsigned int maxIter) override
Definition: solver-HQP-eiquadprog-rt.hxx:225
SolverHQuadProgRT(const std::string &name)
Definition: solver-HQP-eiquadprog-rt.hxx:35
int m_neq
Definition: solver-HQP-eiquadprog-rt.hpp:88
math::Vector Vector
Definition: solver-HQP-eiquadprog-rt.hpp:38
#define EIGEN_MALLOC_ALLOWED
Definition: fwd.hpp:27
#define EIGEN_MALLOC_NOT_ALLOWED
Definition: fwd.hpp:28
Definition: constraint-base.hpp:26
pinocchio::container::aligned_vector< ConstraintLevel > HQPData
Definition: fwd.hpp:99
pinocchio::container::aligned_vector< aligned_pair< double, std::shared_ptr< math::ConstraintBase > > > ConstraintLevel
Definition: fwd.hpp:95
Definition: constraint-bound.hpp:25
std::string toString(const T &v)
Definition: utils.hpp:39
#define PROFILE_EIQUADPROG_SOLUTION
Definition: solver-HQP-eiquadprog-rt.hxx:29
#define PROFILE_EIQUADPROG_PREPARATION
Definition: solver-HQP-eiquadprog-rt.hxx:28
#define DEFAULT_HESSIAN_REGULARIZATION
Definition: fwd.hpp:28
HQP_STATUS_MAX_ITER_REACHED
Definition: fwd.hpp:66
HQP_STATUS_OPTIMAL
Definition: fwd.hpp:63
HQP_STATUS_INFEASIBLE
Definition: fwd.hpp:64