GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: include/eiquadprog/eiquadprog-fast.hpp Lines: 12 13 92.3 %
Date: 2023-11-29 12:38:05 Branches: 13 26 50.0 %

Line Branch Exec Source
1
//
2
// Copyright (c) 2017 CNRS
3
//
4
// This file is part of eiquadprog.
5
//
6
// eiquadprog is free software: you can redistribute it and/or modify
7
// it under the terms of the GNU Lesser General Public License as published by
8
// the Free Software Foundation, either version 3 of the License, or
9
//(at your option) any later version.
10
11
// eiquadprog is distributed in the hope that it will be useful,
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14
// GNU Lesser General Public License for more details.
15
16
// You should have received a copy of the GNU Lesser General Public License
17
// along with eiquadprog.  If not, see <https://www.gnu.org/licenses/>.
18
19
#ifndef EIQUADPROGFAST_HPP_
20
#define EIQUADPROGFAST_HPP_
21
22
#include <Eigen/Dense>
23
24
#define OPTIMIZE_STEP_1_2  // compute s(x) = ci^T * x + ci0
25
#define OPTIMIZE_COMPUTE_D
26
#define OPTIMIZE_UPDATE_Z
27
#define OPTIMIZE_HESSIAN_INVERSE
28
#define OPTIMIZE_UNCONSTR_MINIM
29
30
// #define USE_WARM_START
31
// #define PROFILE_EIQUADPROG
32
33
// #define DEBUG_STREAM(msg) std::cout<<msg;
34
#define DEBUG_STREAM(msg)
35
36
#ifdef PROFILE_EIQUADPROG
37
#define START_PROFILER_EIQUADPROG_FAST(x) START_PROFILER(x)
38
#define STOP_PROFILER_EIQUADPROG_FAST(x) STOP_PROFILER(x)
39
#else
40
#define START_PROFILER_EIQUADPROG_FAST(x)
41
#define STOP_PROFILER_EIQUADPROG_FAST(x)
42
#endif
43
44
#define EIQUADPROG_FAST_CHOLESKY_DECOMPOSITION "EIQUADPROG_FAST Cholesky dec"
45
#define EIQUADPROG_FAST_CHOLESKY_INVERSE "EIQUADPROG_FAST Cholesky inv"
46
#define EIQUADPROG_FAST_ADD_EQ_CONSTR "EIQUADPROG_FAST ADD_EQ_CONSTR"
47
#define EIQUADPROG_FAST_ADD_EQ_CONSTR_1 "EIQUADPROG_FAST ADD_EQ_CONSTR_1"
48
#define EIQUADPROG_FAST_ADD_EQ_CONSTR_2 "EIQUADPROG_FAST ADD_EQ_CONSTR_2"
49
#define EIQUADPROG_FAST_STEP_1 "EIQUADPROG_FAST STEP_1"
50
#define EIQUADPROG_FAST_STEP_1_1 "EIQUADPROG_FAST STEP_1_1"
51
#define EIQUADPROG_FAST_STEP_1_2 "EIQUADPROG_FAST STEP_1_2"
52
#define EIQUADPROG_FAST_STEP_1_UNCONSTR_MINIM \
53
  "EIQUADPROG_FAST STEP_1_UNCONSTR_MINIM"
54
#define EIQUADPROG_FAST_STEP_2 "EIQUADPROG_FAST STEP_2"
55
#define EIQUADPROG_FAST_STEP_2A "EIQUADPROG_FAST STEP_2A"
56
#define EIQUADPROG_FAST_STEP_2B "EIQUADPROG_FAST STEP_2B"
57
#define EIQUADPROG_FAST_STEP_2C "EIQUADPROG_FAST STEP_2C"
58
59
#define DEFAULT_MAX_ITER 1000
60
61
#include "eiquadprog/eiquadprog-utils.hxx"
62
63
namespace eiquadprog {
64
65
namespace solvers {
66
67
/**
68
 * Possible states of the solver.
69
 */
70
enum EiquadprogFast_status {
71
  EIQUADPROG_FAST_OPTIMAL = 0,
72
  EIQUADPROG_FAST_INFEASIBLE = 1,
73
  EIQUADPROG_FAST_UNBOUNDED = 2,
74
  EIQUADPROG_FAST_MAX_ITER_REACHED = 3,
75
  EIQUADPROG_FAST_REDUNDANT_EQUALITIES = 4
76
};
77
78
class EiquadprogFast {
79
  typedef Eigen::MatrixXd MatrixXd;
80
  typedef Eigen::VectorXd VectorXd;
81
  typedef Eigen::VectorXi VectorXi;
82
83
 public:
84
  EIGEN_MAKE_ALIGNED_OPERATOR_NEW
85
86
  EiquadprogFast();
87
  virtual ~EiquadprogFast();
88
89
  void reset(size_t dim_qp, size_t num_eq, size_t num_ineq);
90
91
  int getMaxIter() const { return m_maxIter; }
92
93
  bool setMaxIter(int maxIter) {
94
    if (maxIter < 0) return false;
95
    m_maxIter = maxIter;
96
    return true;
97
  }
98
99
  /**
100
   * @return The size of the active set, namely the number of
101
   * active constraints (including the equalities).
102
   */
103
  size_t getActiveSetSize() const { return q; }
104
105
  /**
106
   * @return The number of active-set iteratios.
107
   */
108
  int getIteratios() const { return iter; }
109
110
  /**
111
   * @return The value of the objective function.
112
   */
113
7
  double getObjValue() const { return f_value; }
114
115
  /**
116
   * @return The Lagrange multipliers
117
   */
118
  const VectorXd& getLagrangeMultipliers() const { return u; }
119
120
  /**
121
   * Return the active set, namely the indeces of active constraints.
122
   * The first nEqCon indexes are for the equalities and are negative.
123
   * The last nIneqCon indexes are for the inequalities and start from 0.
124
   * Only the first q elements of the return vector are valid, where q
125
   * is the size of the active set.
126
   * @return The set of indexes of the active constraints.
127
   */
128
  const VectorXi& getActiveSet() const { return A; }
129
130
  /**
131
   * solves the problem
132
   * min. x' Hess x + 2 g0' x
133
   * s.t. CE x + ce0 = 0
134
   *      CI x + ci0 >= 0
135
   */
136
  EiquadprogFast_status solve_quadprog(const MatrixXd& Hess, const VectorXd& g0,
137
                                       const MatrixXd& CE, const VectorXd& ce0,
138
                                       const MatrixXd& CI, const VectorXd& ci0,
139
                                       VectorXd& x);
140
141
  MatrixXd m_J;  // J * J' = Hessian <nVars,nVars>::d
142
  bool is_inverse_provided_;
143
144
 private:
145
  size_t m_nVars;
146
  size_t m_nEqCon;
147
  size_t m_nIneqCon;
148
149
  int m_maxIter;   /// max number of active-set iterations
150
  double f_value;  /// current value of cost function
151
152
  Eigen::LLT<MatrixXd, Eigen::Lower> chol_;  // <nVars,nVars>::d
153
154
  /// from QR of L' N, where L is Cholewsky factor of Hessian, and N is the
155
  /// matrix of active constraints
156
  MatrixXd R;  // <nVars,nVars>::d
157
158
  /// CI*x+ci0
159
  VectorXd s;  // <nIneqCon>::d
160
161
  /// infeasibility multipliers, i.e. negative step direction in dual space
162
  VectorXd r;  // <nIneqCon+nEqCon>::d
163
164
  /// Lagrange multipliers
165
  VectorXd u;  // <nIneqCon+nEqCon>::d
166
167
  /// step direction in primal space
168
  VectorXd z;  // <nVars>::d
169
170
  /// J' np
171
  VectorXd d;  //<nVars>::d
172
173
  /// current constraint normal
174
  VectorXd np;  //<nVars>::d
175
176
  /// active set (indeces of active constraints)
177
  /// the first nEqCon indeces are for the equalities and are negative
178
  /// the last nIneqCon indeces are for the inequalities are start from 0
179
  VectorXi A;  // <nIneqCon+nEqCon>
180
181
  /// initialized as K \ A
182
  /// iai(i)=-1 iff inequality constraint i is in the active set
183
  /// iai(i)=i otherwise
184
  VectorXi iai;  // <nIneqCon>::i
185
186
  /// initialized as [1, ..., 1, .]
187
  /// if iaexcl(i)!=1 inequality constraint i cannot be added to the active set
188
  /// if adding ineq constraint i fails => iaexcl(i)=0
189
  /// iaexcl(i)=0 iff ineq constraint i is linearly dependent to other active
190
  /// constraints iaexcl(i)=1 otherwise
191
  VectorXi iaexcl;  //<nIneqCon>::i
192
193
  VectorXd x_old;  // old value of x <nVars>::d
194
  VectorXd u_old;  // old value of u <nIneqCon+nEqCon>::d
195
  VectorXi A_old;  // old value of A <nIneqCon+nEqCon>::i
196
197
#ifdef OPTIMIZE_ADD_CONSTRAINT
198
  VectorXd T1;  /// tmp variable used in add_constraint
199
#endif
200
201
  /// size of the active set A (containing the indices of the active
202
  /// constraints)
203
  size_t q;
204
205
  /// number of active-set iterations
206
  int iter;
207
208
12
  inline void compute_d(VectorXd& d, const MatrixXd& J, const VectorXd& np) {
209
#ifdef OPTIMIZE_COMPUTE_D
210

12
    d.noalias() = J.adjoint() * np;
211
#else
212
    d = J.adjoint() * np;
213
#endif
214
12
  }
215
216
11
  inline void update_z(VectorXd& z, const MatrixXd& J, const VectorXd& d,
217
                       size_t iq) {
218
#ifdef OPTIMIZE_UPDATE_Z
219


11
    z.noalias() = J.rightCols(z.size() - iq) * d.tail(z.size() - iq);
220
#else
221
    z = J.rightCols(J.cols() - iq) * d.tail(J.cols() - iq);
222
#endif
223
11
  }
224
225
12
  inline void update_r(const MatrixXd& R, VectorXd& r, const VectorXd& d,
226
                       size_t iq) {
227

12
    r.head(iq) = d.head(iq);
228

24
    R.topLeftCorner(iq, iq).triangularView<Eigen::Upper>().solveInPlace(
229
12
        r.head(iq));
230
12
  }
231
232
  inline bool add_constraint(MatrixXd& R, MatrixXd& J, VectorXd& d, size_t& iq,
233
                             double& R_norm);
234
235
  inline void delete_constraint(MatrixXd& R, MatrixXd& J, VectorXi& A,
236
                                VectorXd& u, size_t nEqCon, size_t& iq,
237
                                size_t l);
238
};
239
240
} /* namespace solvers */
241
} /* namespace eiquadprog */
242
243
#endif /* EIQUADPROGFAST_HPP_ */