active_set.cpp 6.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202
  1. #include "active_set.h"
  2. #include "min_quad_with_fixed.h"
  3. #include "slice.h"
  4. #include <iostream>
  5. #include <limits>
  6. #include <algorithm>
  7. template <
  8. typename AT,
  9. typename DerivedB,
  10. typename Derivedknown,
  11. typename DerivedY,
  12. typename AeqT,
  13. typename DerivedBeq,
  14. typename AieqT,
  15. typename DerivedBieq,
  16. typename Derivedlx,
  17. typename Derivedux,
  18. typename DerivedZ
  19. >
  20. IGL_INLINE igl::SolverStatus igl::active_set(
  21. const Eigen::SparseMatrix<AT>& A,
  22. const Eigen::PlainObjectBase<DerivedB> & B,
  23. const Eigen::PlainObjectBase<Derivedknown> & known,
  24. const Eigen::PlainObjectBase<DerivedY> & Y,
  25. const Eigen::SparseMatrix<AeqT>& Aeq,
  26. const Eigen::PlainObjectBase<DerivedBeq> & Beq,
  27. const Eigen::SparseMatrix<AieqT>& Aieq,
  28. const Eigen::PlainObjectBase<DerivedBieq> & Bieq,
  29. const Eigen::PlainObjectBase<Derivedlx> & lx,
  30. const Eigen::PlainObjectBase<Derivedux> & ux,
  31. const igl::active_set_params & params,
  32. Eigen::PlainObjectBase<DerivedZ> & Z
  33. )
  34. {
  35. using namespace igl;
  36. using namespace Eigen;
  37. using namespace std;
  38. // Linear inequality constraints are not supported yet
  39. assert(Aieq.size() == 0);
  40. assert(Bieq.size() == 0);
  41. SolverStatus ret = SOLVER_STATUS_ERROR;
  42. const int n = A.rows();
  43. assert(n == A.cols());
  44. // Discard const qualifiers
  45. //if(B.size() == 0)
  46. //{
  47. // B = Eigen::PlainObjectBase<DerivedB>::Zero(n,1);
  48. //}
  49. assert(n == B.rows());
  50. assert(B.cols() == 1);
  51. assert(Y.cols() == 1);
  52. assert((Aeq.size() == 0 && Beq.size() == 0) || Aeq.cols() == n);
  53. assert((Aeq.size() == 0 && Beq.size() == 0) || Aeq.rows() == Beq.rows());
  54. assert((Aeq.size() == 0 && Beq.size() == 0) || Beq.cols() == 1);
  55. assert((Aieq.size() == 0 && Bieq.size() == 0) || Aieq.cols() == n);
  56. assert((Aieq.size() == 0 && Bieq.size() == 0) || Aieq.rows() == Bieq.rows());
  57. assert((Aieq.size() == 0 && Bieq.size() == 0) || Bieq.cols() == 1);
  58. // Discard const qualifiers
  59. //if(lx.size() == 0)
  60. //{
  61. // lx = Eigen::PlainObjectBase<Derivedlx>::Constant(
  62. // n,1,numeric_limits<typename Derivedlx::Scalar>::min());
  63. //}
  64. //if(ux.size() == 0)
  65. //{
  66. // ux = Eigen::PlainObjectBase<Derivedux>::Constant(
  67. // n,1,numeric_limits<typename Derivedux::Scalar>::max());
  68. //}
  69. assert(lx.rows() == n);
  70. assert(ux.rows() == n);
  71. assert(ux.cols() == 1);
  72. assert(lx.cols() == 1);
  73. assert((ux.array()-lx.array()).minCoeff() > 0);
  74. if(Z.size() != 0)
  75. {
  76. // Initial guess should have correct size
  77. assert(Z.rows() == n);
  78. assert(Z.cols() == 1);
  79. }
  80. // Initialize active sets
  81. Matrix<bool,Dynamic,1> as_lx(n,1);
  82. Matrix<bool,Dynamic,1> as_ux(n,1);
  83. Matrix<bool,Dynamic,1> as_ieq(Aieq.rows(),1);
  84. int iter = 0;
  85. while(true)
  86. {
  87. // FIND BREACHES OF CONSTRAINTS
  88. if(Z.size() > 0)
  89. {
  90. for(int z = 0;z < n;z++)
  91. {
  92. if(Z(z) < lx(z))
  93. {
  94. as_lx(z) = true;
  95. }
  96. if(Z(z) > ux(z))
  97. {
  98. as_ux(z) = true;
  99. }
  100. }
  101. }
  102. const int as_lx_count = count(as_lx.data(),as_lx.data()+n,true);
  103. const int as_ux_count = count(as_ux.data(),as_ux.data()+n,true);
  104. // PREPARE FIXED VALUES
  105. Eigen::PlainObjectBase<Derivedknown> known_i;
  106. known_i.resize((int)known.size() + as_lx_count + as_ux_count,1);
  107. Eigen::PlainObjectBase<DerivedY> Y_i;
  108. Y_i.resize((int)known.size() + as_lx_count + as_ux_count,1);
  109. {
  110. known_i.block(0,0,known.rows(),known.cols()) = known;
  111. Y_i.block(0,0,Y.rows(),Y.cols()) = Y;
  112. int k = known.size();
  113. // Then all lx
  114. for(int z = 0;z < n;z++)
  115. {
  116. if(as_lx(z))
  117. {
  118. known_i(k) = z;
  119. Y_i(k) = lx(z);
  120. k++;
  121. }
  122. }
  123. // Finally all ux
  124. for(int z = 0;z < n;z++)
  125. {
  126. if(as_ux(z))
  127. {
  128. known_i(k) = z;
  129. Y_i(k) = ux(z);
  130. k++;
  131. }
  132. }
  133. assert(k==Y_i.size());
  134. assert(k==known_i.size());
  135. }
  136. min_quad_with_fixed_data<AT> data;
  137. if(!min_quad_with_fixed_precompute(A,known_i,Aeq,params.Auu_pd,data))
  138. {
  139. cerr<<"Error: min_quad_with_fixed precomputation failed."<<endl;
  140. ret = SOLVER_STATUS_ERROR;
  141. break;
  142. }
  143. if(!min_quad_with_fixed_solve(data,B,Y_i,Beq,Z))
  144. {
  145. cerr<<"Error: min_quad_with_fixed solve failed."<<endl;
  146. ret = SOLVER_STATUS_ERROR;
  147. break;
  148. }
  149. // Compute Lagrange multiplier values for known_i
  150. // This needs to be adjusted slightly if A is not symmetric
  151. assert(data.Auu_sym);
  152. SparseMatrix<AT> Ak;
  153. // Slow
  154. slice(A,known_i,1,Ak);
  155. Eigen::PlainObjectBase<DerivedB> Bk;
  156. slice(B,known_i,Bk);
  157. MatrixXd Lambda_known_i = -(Ak*Z + 0.5*Bk);
  158. // reverse the lambda values for lx
  159. Lambda_known_i.block(known.size(),0,as_lx_count,1) =
  160. (-1*Lambda_known_i.block(known.size(),0,as_lx_count,1)).eval();
  161. // Remove from active set
  162. for(int z = 0;z<as_lx_count;z++)
  163. {
  164. if(Lambda_known_i(known.size() + z) < params.inactive_threshold)
  165. {
  166. as_lx(known_i(z)) = false;
  167. }
  168. }
  169. for(int z = 0;z<as_ux_count;z++)
  170. {
  171. if(Lambda_known_i(known.size() + as_lx_count + z) <
  172. params.inactive_threshold)
  173. {
  174. as_ux(known_i(z)) = false;
  175. }
  176. }
  177. iter++;
  178. if(params.max_iter>0 && iter>=params.max_iter)
  179. {
  180. ret = SOLVER_STATUS_MAX_ITER;
  181. break;
  182. }
  183. }
  184. finish:
  185. return ret;
  186. }
  187. #ifndef IGL_HEADER_ONLY
  188. // Explicit template specialization
  189. template igl::SolverStatus igl::active_set<double, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, double, Eigen::Matrix<double, -1, 1, 0, -1, 1>, double, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::SparseMatrix<double, 0, int> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<double, 0, int> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::SparseMatrix<double, 0, int> const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> > const&, igl::active_set_params const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
  190. #endif