Program Listing for File eiquadprog-fast.hpp

Return to documentation for file (include/eiquadprog/eiquadprog-fast.hpp)

//
// Copyright (c) 2017 CNRS
//
// This file is part of eiquadprog.
//
// eiquadprog is free software: you can redistribute it and/or modify
// it under the terms of the GNU Lesser General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
//(at your option) any later version.

// eiquadprog is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU Lesser General Public License for more details.

// You should have received a copy of the GNU Lesser General Public License
// along with eiquadprog.  If not, see <https://www.gnu.org/licenses/>.

#ifndef EIQUADPROGFAST_HPP_
#define EIQUADPROGFAST_HPP_

#include <Eigen/Dense>

#define OPTIMIZE_STEP_1_2  // compute s(x) = ci^T * x + ci0
#define OPTIMIZE_COMPUTE_D
#define OPTIMIZE_UPDATE_Z
#define OPTIMIZE_HESSIAN_INVERSE
#define OPTIMIZE_UNCONSTR_MINIM

// #define USE_WARM_START
// #define PROFILE_EIQUADPROG

// #define DEBUG_STREAM(msg) std::cout<<msg;
#define DEBUG_STREAM(msg)

#ifdef PROFILE_EIQUADPROG
#define START_PROFILER_EIQUADPROG_FAST(x) START_PROFILER(x)
#define STOP_PROFILER_EIQUADPROG_FAST(x) STOP_PROFILER(x)
#else
#define START_PROFILER_EIQUADPROG_FAST(x)
#define STOP_PROFILER_EIQUADPROG_FAST(x)
#endif

#define EIQUADPROG_FAST_CHOLESKY_DECOMPOSITION "EIQUADPROG_FAST Cholesky dec"
#define EIQUADPROG_FAST_CHOLESKY_INVERSE "EIQUADPROG_FAST Cholesky inv"
#define EIQUADPROG_FAST_ADD_EQ_CONSTR "EIQUADPROG_FAST ADD_EQ_CONSTR"
#define EIQUADPROG_FAST_ADD_EQ_CONSTR_1 "EIQUADPROG_FAST ADD_EQ_CONSTR_1"
#define EIQUADPROG_FAST_ADD_EQ_CONSTR_2 "EIQUADPROG_FAST ADD_EQ_CONSTR_2"
#define EIQUADPROG_FAST_STEP_1 "EIQUADPROG_FAST STEP_1"
#define EIQUADPROG_FAST_STEP_1_1 "EIQUADPROG_FAST STEP_1_1"
#define EIQUADPROG_FAST_STEP_1_2 "EIQUADPROG_FAST STEP_1_2"
#define EIQUADPROG_FAST_STEP_1_UNCONSTR_MINIM \
  "EIQUADPROG_FAST STEP_1_UNCONSTR_MINIM"
#define EIQUADPROG_FAST_STEP_2 "EIQUADPROG_FAST STEP_2"
#define EIQUADPROG_FAST_STEP_2A "EIQUADPROG_FAST STEP_2A"
#define EIQUADPROG_FAST_STEP_2B "EIQUADPROG_FAST STEP_2B"
#define EIQUADPROG_FAST_STEP_2C "EIQUADPROG_FAST STEP_2C"

#define DEFAULT_MAX_ITER 1000

#include "eiquadprog/eiquadprog-utils.hxx"

namespace eiquadprog {

namespace solvers {

enum EiquadprogFast_status {
  EIQUADPROG_FAST_OPTIMAL = 0,
  EIQUADPROG_FAST_INFEASIBLE = 1,
  EIQUADPROG_FAST_UNBOUNDED = 2,
  EIQUADPROG_FAST_MAX_ITER_REACHED = 3,
  EIQUADPROG_FAST_REDUNDANT_EQUALITIES = 4
};

class EiquadprogFast {
  typedef Eigen::MatrixXd MatrixXd;
  typedef Eigen::VectorXd VectorXd;
  typedef Eigen::VectorXi VectorXi;

 public:
  EIGEN_MAKE_ALIGNED_OPERATOR_NEW

  EiquadprogFast();
  virtual ~EiquadprogFast();

  void reset(size_t dim_qp, size_t num_eq, size_t num_ineq);

  int getMaxIter() const { return m_maxIter; }

  bool setMaxIter(int maxIter) {
    if (maxIter < 0) return false;
    m_maxIter = maxIter;
    return true;
  }

  size_t getActiveSetSize() const { return q; }

  int getIteratios() const { return iter; }

  double getObjValue() const { return f_value; }

  const VectorXd& getLagrangeMultipliers() const { return u; }

  const VectorXi& getActiveSet() const { return A; }

  EiquadprogFast_status solve_quadprog(const MatrixXd& Hess, const VectorXd& g0,
                                       const MatrixXd& CE, const VectorXd& ce0,
                                       const MatrixXd& CI, const VectorXd& ci0,
                                       VectorXd& x);

  MatrixXd m_J;  // J * J' = Hessian <nVars,nVars>::d
  bool is_inverse_provided_;

 private:
  size_t m_nVars;
  size_t m_nEqCon;
  size_t m_nIneqCon;

  int m_maxIter;
  double f_value;

  Eigen::LLT<MatrixXd, Eigen::Lower> chol_;  // <nVars,nVars>::d

  MatrixXd R;  // <nVars,nVars>::d

  VectorXd s;  // <nIneqCon>::d

  VectorXd r;  // <nIneqCon+nEqCon>::d

  VectorXd u;  // <nIneqCon+nEqCon>::d

  VectorXd z;  // <nVars>::d

  VectorXd d;  //<nVars>::d

  VectorXd np;  //<nVars>::d

  VectorXi A;  // <nIneqCon+nEqCon>

  VectorXi iai;  // <nIneqCon>::i

  VectorXi iaexcl;  //<nIneqCon>::i

  VectorXd x_old;  // old value of x <nVars>::d
  VectorXd u_old;  // old value of u <nIneqCon+nEqCon>::d
  VectorXi A_old;  // old value of A <nIneqCon+nEqCon>::i

#ifdef OPTIMIZE_ADD_CONSTRAINT
  VectorXd T1;
#endif

  size_t q;

  int iter;

  inline void compute_d(VectorXd& d, const MatrixXd& J, const VectorXd& np) {
#ifdef OPTIMIZE_COMPUTE_D
    d.noalias() = J.adjoint() * np;
#else
    d = J.adjoint() * np;
#endif
  }

  inline void update_z(VectorXd& z, const MatrixXd& J, const VectorXd& d,
                       size_t iq) {
#ifdef OPTIMIZE_UPDATE_Z
    z.noalias() = J.rightCols(z.size() - iq) * d.tail(z.size() - iq);
#else
    z = J.rightCols(J.cols() - iq) * d.tail(J.cols() - iq);
#endif
  }

  inline void update_r(const MatrixXd& R, VectorXd& r, const VectorXd& d,
                       size_t iq) {
    r.head(iq) = d.head(iq);
    R.topLeftCorner(iq, iq).triangularView<Eigen::Upper>().solveInPlace(
        r.head(iq));
  }

  inline bool add_constraint(MatrixXd& R, MatrixXd& J, VectorXd& d, size_t& iq,
                             double& R_norm);

  inline void delete_constraint(MatrixXd& R, MatrixXd& J, VectorXi& A,
                                VectorXd& u, size_t nEqCon, size_t& iq,
                                size_t l);
};

} /* namespace solvers */
} /* namespace eiquadprog */

#endif /* EIQUADPROGFAST_HPP_ */