quadprog.cpp 8.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. #include "quadprog.h"
  2. #include "min_quad_with_fixed.h"
  3. #include <iostream>
  4. template <typename Scalar, int n, int m>
  5. IGL_INLINE Eigen::Matrix<Scalar,n,1> igl::quadprog(
  6. const Eigen::Matrix<Scalar,n,n> & H,
  7. const Eigen::Matrix<Scalar,n,1> & f,
  8. const Eigen::Matrix<Scalar,m,n> & A,
  9. const Eigen::Matrix<Scalar,m,1> & b,
  10. const Eigen::Matrix<Scalar,n,1> & lb,
  11. const Eigen::Matrix<Scalar,n,1> & ub)
  12. {
  13. // Alec 16/2/2021:
  14. // igl::quadprog implements a very simple primal active set method. The new
  15. // igl::min_quad_with_fixed is very fast for small dense problems so the
  16. // iterations of igl::quadprog become very fast. Even if it ends up doing many
  17. // more iterations than igl::copyleft::quadprog it would be much faster (in
  18. // reality it doesn't do that many more iterations). It's a healthy 10-100x
  19. // faster than igl::copyleft::quadprog for specific cases of QPs.
  20. //
  21. // Unfortunately, that set is limited. igl::quadprog is really good at tiny
  22. // box-constrained QPs with a positive definite objective (like the kind that show
  23. // up in dual contouring). igl::copyleft::quadprog handles more general problems
  24. // (and also starts to beat igl::quadprog when the number of variables gets over
  25. // ~20). I tried extending igl::quadprog so that we could use it for
  26. // igl::copyleft::progressive_hulls and drop igl::copyleft::quadprog but it was
  27. // trickier than I thought. Something like qpmad or the non GPL version of
  28. // quadrog++ would be good future PR.
  29. //
  30. typedef Eigen::Matrix<Scalar,n,1> VectorSn;
  31. typedef Eigen::Array<bool,n,1> Arraybn;
  32. assert( (lb.array() < ub.array() ).all() );
  33. const int dyn_n = n == Eigen::Dynamic ? H.rows() : n;
  34. VectorSn x(dyn_n);
  35. VectorSn bc = VectorSn::Constant(dyn_n,1,-1e26);
  36. Arraybn k = Arraybn::Constant(dyn_n,1,false);
  37. Eigen::Index iter;
  38. // n³ is probably way too conservative.
  39. for(iter = 0;iter<dyn_n*dyn_n*dyn_n;iter++)
  40. {
  41. // For dual contouring 99% of the time the active set is empty.
  42. // Optimize for this common case.
  43. // Windows needs template arguments spelled out
  44. x = min_quad_with_fixed<Scalar,n,m>(H,f,k,bc,A,b);
  45. // constraint violations
  46. VectorSn vl = lb-x;
  47. VectorSn vu = x-ub;
  48. // try to add/remove constraints
  49. Eigen::Index best_add = -1; Scalar worst_offense = 0;
  50. bool add_lower;
  51. Eigen::Index best_remove = -1; Scalar worst_lambda = 0;
  52. for(Eigen::Index i = 0;i<dyn_n;i++)
  53. {
  54. if(vl(i)>worst_offense)
  55. {
  56. best_add = i;
  57. add_lower = true;
  58. worst_offense = vl(i);
  59. }
  60. if(vu(i)>worst_offense)
  61. {
  62. best_add = i;
  63. add_lower = false;
  64. worst_offense = vu(i);
  65. }
  66. // bias toward adding constraints
  67. if(best_add<0 && k(i))
  68. {
  69. const Scalar sign = bc(i)==ub(i)?1:-1;
  70. const Scalar lambda_i = sign * (H.row(i)*x+f(i));
  71. if(lambda_i > worst_lambda)
  72. {
  73. best_remove = i;
  74. worst_lambda = lambda_i;
  75. }
  76. }
  77. }
  78. // bias toward adding constraints
  79. if(best_add >= 0)
  80. {
  81. const auto i = best_add;
  82. assert(!k(i));
  83. bc(i) = add_lower ? lb(i) : ub(i);
  84. k(i) = true;
  85. }else if(best_remove >= 0)
  86. {
  87. const auto i = best_remove;
  88. assert(k(i));
  89. k(i) = false;
  90. }else /*if(best_add < 0 && best_remove < 0)*/
  91. {
  92. return x;
  93. }
  94. }
  95. // Should never happen.
  96. assert(false && "quadprog failed after too many iterations");
  97. return VectorSn::Zero(dyn_n);
  98. }
  99. template <typename Scalar, int n>
  100. IGL_INLINE Eigen::Matrix<Scalar,n,1> igl::quadprog(
  101. const Eigen::Matrix<Scalar,n,n> & H,
  102. const Eigen::Matrix<Scalar,n,1> & f,
  103. const Eigen::Matrix<Scalar,n,1> & lb,
  104. const Eigen::Matrix<Scalar,n,1> & ub)
  105. {
  106. const int m = n == Eigen::Dynamic ? Eigen::Dynamic : 0;
  107. // Windows needs template parameters spelled out
  108. return quadprog<Scalar,n,m>(
  109. H,f,
  110. Eigen::Matrix<Scalar,m,n>(0,H.cols()),
  111. Eigen::Matrix<Scalar,m,1>(0,1),
  112. lb,ub);
  113. }
  114. #ifdef IGL_STATIC_LIBRARY
  115. // Explicit template instantiation
  116. template Eigen::Matrix<double, 2, 1, ((Eigen::StorageOptions)0) | ((((2) == (1)) && ((1) != (1))) ? ((Eigen::StorageOptions)1) : ((((1) == (1)) && ((2) != (1))) ? ((Eigen::StorageOptions)0) : ((Eigen::StorageOptions)0))), 2, 1> igl::quadprog<double, 2>(Eigen::Matrix<double, 2, 2, ((Eigen::StorageOptions)0) | ((((2) == (1)) && ((2) != (1))) ? ((Eigen::StorageOptions)1) : ((((2) == (1)) && ((2) != (1))) ? ((Eigen::StorageOptions)0) : ((Eigen::StorageOptions)0))), 2, 2> const&, Eigen::Matrix<double, 2, 1, ((Eigen::StorageOptions)0) | ((((2) == (1)) && ((1) != (1))) ? ((Eigen::StorageOptions)1) : ((((1) == (1)) && ((2) != (1))) ? ((Eigen::StorageOptions)0) : ((Eigen::StorageOptions)0))), 2, 1> const&, Eigen::Matrix<double, 2, 1, ((Eigen::StorageOptions)0) | ((((2) == (1)) && ((1) != (1))) ? ((Eigen::StorageOptions)1) : ((((1) == (1)) && ((2) != (1))) ? ((Eigen::StorageOptions)0) : ((Eigen::StorageOptions)0))), 2, 1> const&, Eigen::Matrix<double, 2, 1, ((Eigen::StorageOptions)0) | ((((2) == (1)) && ((1) != (1))) ? ((Eigen::StorageOptions)1) : ((((1) == (1)) && ((2) != (1))) ? ((Eigen::StorageOptions)0) : ((Eigen::StorageOptions)0))), 2, 1> const&);
  117. template Eigen::Matrix<double, 3, 1, ((Eigen::StorageOptions)0) | ((((3) == (1)) && ((1) != (1))) ? ((Eigen::StorageOptions)1) : ((((1) == (1)) && ((3) != (1))) ? ((Eigen::StorageOptions)0) : ((Eigen::StorageOptions)0))), 3, 1> igl::quadprog<double, 3>(Eigen::Matrix<double, 3, 3, ((Eigen::StorageOptions)0) | ((((3) == (1)) && ((3) != (1))) ? ((Eigen::StorageOptions)1) : ((((3) == (1)) && ((3) != (1))) ? ((Eigen::StorageOptions)0) : ((Eigen::StorageOptions)0))), 3, 3> const&, Eigen::Matrix<double, 3, 1, ((Eigen::StorageOptions)0) | ((((3) == (1)) && ((1) != (1))) ? ((Eigen::StorageOptions)1) : ((((1) == (1)) && ((3) != (1))) ? ((Eigen::StorageOptions)0) : ((Eigen::StorageOptions)0))), 3, 1> const&, Eigen::Matrix<double, 3, 1, ((Eigen::StorageOptions)0) | ((((3) == (1)) && ((1) != (1))) ? ((Eigen::StorageOptions)1) : ((((1) == (1)) && ((3) != (1))) ? ((Eigen::StorageOptions)0) : ((Eigen::StorageOptions)0))), 3, 1> const&, Eigen::Matrix<double, 3, 1, ((Eigen::StorageOptions)0) | ((((3) == (1)) && ((1) != (1))) ? ((Eigen::StorageOptions)1) : ((((1) == (1)) && ((3) != (1))) ? ((Eigen::StorageOptions)0) : ((Eigen::StorageOptions)0))), 3, 1> const&);
  118. template Eigen::Matrix<float, 2, 1, ((Eigen::StorageOptions)0) | ((((2) == (1)) && ((1) != (1))) ? ((Eigen::StorageOptions)1) : ((((1) == (1)) && ((2) != (1))) ? ((Eigen::StorageOptions)0) : ((Eigen::StorageOptions)0))), 2, 1> igl::quadprog<float, 2>(Eigen::Matrix<float, 2, 2, ((Eigen::StorageOptions)0) | ((((2) == (1)) && ((2) != (1))) ? ((Eigen::StorageOptions)1) : ((((2) == (1)) && ((2) != (1))) ? ((Eigen::StorageOptions)0) : ((Eigen::StorageOptions)0))), 2, 2> const&, Eigen::Matrix<float, 2, 1, ((Eigen::StorageOptions)0) | ((((2) == (1)) && ((1) != (1))) ? ((Eigen::StorageOptions)1) : ((((1) == (1)) && ((2) != (1))) ? ((Eigen::StorageOptions)0) : ((Eigen::StorageOptions)0))), 2, 1> const&, Eigen::Matrix<float, 2, 1, ((Eigen::StorageOptions)0) | ((((2) == (1)) && ((1) != (1))) ? ((Eigen::StorageOptions)1) : ((((1) == (1)) && ((2) != (1))) ? ((Eigen::StorageOptions)0) : ((Eigen::StorageOptions)0))), 2, 1> const&, Eigen::Matrix<float, 2, 1, ((Eigen::StorageOptions)0) | ((((2) == (1)) && ((1) != (1))) ? ((Eigen::StorageOptions)1) : ((((1) == (1)) && ((2) != (1))) ? ((Eigen::StorageOptions)0) : ((Eigen::StorageOptions)0))), 2, 1> const&);
  119. template Eigen::Matrix<float, 3, 1, ((Eigen::StorageOptions)0) | ((((3) == (1)) && ((1) != (1))) ? ((Eigen::StorageOptions)1) : ((((1) == (1)) && ((3) != (1))) ? ((Eigen::StorageOptions)0) : ((Eigen::StorageOptions)0))), 3, 1> igl::quadprog<float, 3>(Eigen::Matrix<float, 3, 3, ((Eigen::StorageOptions)0) | ((((3) == (1)) && ((3) != (1))) ? ((Eigen::StorageOptions)1) : ((((3) == (1)) && ((3) != (1))) ? ((Eigen::StorageOptions)0) : ((Eigen::StorageOptions)0))), 3, 3> const&, Eigen::Matrix<float, 3, 1, ((Eigen::StorageOptions)0) | ((((3) == (1)) && ((1) != (1))) ? ((Eigen::StorageOptions)1) : ((((1) == (1)) && ((3) != (1))) ? ((Eigen::StorageOptions)0) : ((Eigen::StorageOptions)0))), 3, 1> const&, Eigen::Matrix<float, 3, 1, ((Eigen::StorageOptions)0) | ((((3) == (1)) && ((1) != (1))) ? ((Eigen::StorageOptions)1) : ((((1) == (1)) && ((3) != (1))) ? ((Eigen::StorageOptions)0) : ((Eigen::StorageOptions)0))), 3, 1> const&, Eigen::Matrix<float, 3, 1, ((Eigen::StorageOptions)0) | ((((3) == (1)) && ((1) != (1))) ? ((Eigen::StorageOptions)1) : ((((1) == (1)) && ((3) != (1))) ? ((Eigen::StorageOptions)0) : ((Eigen::StorageOptions)0))), 3, 1> const&);
  120. #endif