bbw.cpp 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182
  1. #define VERBOSE
  2. #include "bbw.h"
  3. #include <igl/cotmatrix.h>
  4. #include <igl/massmatrix.h>
  5. #include <igl/invert_diag.h>
  6. #include <igl/speye.h>
  7. #include <igl/slice_into.h>
  8. #include <igl/normalize_row_sums.h>
  9. #include <igl/verbose.h>
  10. #include <igl/min_quad_with_fixed.h>
  11. #define EIGEN_YES_I_KNOW_SPARSE_MODULE_IS_NOT_STABLE_YET
  12. #include <Eigen/Sparse>
  13. #include <iostream>
  14. #include <cstdio>
  15. igl::BBWData::BBWData():
  16. partition_unity(false),
  17. qp_solver(QP_SOLVER_IGL_ACTIVE_SET)
  18. {}
  19. void igl::BBWData::print()
  20. {
  21. using namespace std;
  22. cout<<"partition_unity: "<<partition_unity<<endl;
  23. cout<<"W0=["<<endl<<W0<<endl<<"];"<<endl;
  24. cout<<"qp_solver: "<<QPSolverNames[qp_solver]<<endl;
  25. }
  26. template <
  27. typename DerivedV,
  28. typename DerivedEle,
  29. typename Derivedb,
  30. typename Derivedbc,
  31. typename DerivedW>
  32. IGL_INLINE bool igl::bbw(
  33. const Eigen::PlainObjectBase<DerivedV> & V,
  34. const Eigen::PlainObjectBase<DerivedEle> & Ele,
  35. const Eigen::PlainObjectBase<Derivedb> & b,
  36. const Eigen::PlainObjectBase<Derivedbc> & bc,
  37. igl::BBWData & data,
  38. Eigen::PlainObjectBase<DerivedW> & W
  39. )
  40. {
  41. using namespace igl;
  42. using namespace std;
  43. using namespace Eigen;
  44. // number of domain vertices
  45. int n = V.rows();
  46. // number of handles
  47. int m = bc.cols();
  48. SparseMatrix<typename DerivedW::Scalar> L;
  49. cotmatrix(V,Ele,L);
  50. MassMatrixType mmtype = MASSMATRIX_VORONOI;
  51. if(Ele.cols() == 4)
  52. {
  53. mmtype = MASSMATRIX_BARYCENTRIC;
  54. }
  55. SparseMatrix<typename DerivedW::Scalar> M;
  56. SparseMatrix<typename DerivedW::Scalar> Mi;
  57. massmatrix(V,Ele,mmtype,M);
  58. invert_diag(M,Mi);
  59. // Biharmonic operator
  60. SparseMatrix<typename DerivedW::Scalar> Q = L.transpose() * Mi * L;
  61. W.derived().resize(n,m);
  62. if(data.partition_unity)
  63. {
  64. // Not yet implemented
  65. assert(false);
  66. }else
  67. {
  68. // No linear terms
  69. VectorXd c = VectorXd::Zero(n);
  70. // No linear constraints
  71. SparseMatrix<typename DerivedW::Scalar> A(0,n),Aeq(0,n),Aieq(0,n);
  72. VectorXd uc(0,1),Beq(0,1),Bieq(0,1),lc(0,1);
  73. // Upper and lower box constraints (Constant bounds)
  74. VectorXd ux = VectorXd::Ones(n);
  75. VectorXd lx = VectorXd::Zero(n);
  76. active_set_params eff_params = data.active_set_params;
  77. switch(data.qp_solver)
  78. {
  79. case QP_SOLVER_IGL_ACTIVE_SET:
  80. {
  81. verbose("\n^%s: Computing initial weights for %d handle%s.\n\n",
  82. __FUNCTION__,m,(m!=1?"s":""));
  83. min_quad_with_fixed_data<typename DerivedW::Scalar > mqwf;
  84. min_quad_with_fixed_precompute(Q,b,Aeq,true,mqwf);
  85. min_quad_with_fixed_solve(mqwf,c,bc,Beq,W);
  86. // decrement
  87. eff_params.max_iter--;
  88. bool error = false;
  89. // Loop over handles
  90. #pragma omp parallel for
  91. for(int i = 0;i<m;i++)
  92. {
  93. // Quicker exit for openmp
  94. if(error)
  95. {
  96. continue;
  97. }
  98. verbose("\n^%s: Computing weight for handle %d out of %d.\n\n",
  99. __FUNCTION__,i+1,m);
  100. VectorXd bci = bc.col(i);
  101. VectorXd Wi;
  102. // use initial guess
  103. Wi = W.col(i);
  104. SolverStatus ret = active_set(
  105. Q,c,b,bci,Aeq,Beq,Aieq,Bieq,lx,ux,eff_params,Wi);
  106. switch(ret)
  107. {
  108. case SOLVER_STATUS_CONVERGED:
  109. break;
  110. case SOLVER_STATUS_MAX_ITER:
  111. cout<<"active_set: max iter without convergence."<<endl;
  112. break;
  113. case SOLVER_STATUS_ERROR:
  114. default:
  115. cout<<"active_set error."<<endl;
  116. error = true;
  117. }
  118. W.col(i) = Wi;
  119. }
  120. if(error)
  121. {
  122. return false;
  123. }
  124. break;
  125. }
  126. case QP_SOLVER_MOSEK:
  127. {
  128. // Loop over handles
  129. for(int i = 0;i<m;i++)
  130. {
  131. verbose("\n^%s: Computing weight for handle %d out of %d.\n\n",
  132. __FUNCTION__,i+1,m);
  133. VectorXd bci = bc.col(i);
  134. VectorXd Wi;
  135. // impose boundary conditions via bounds
  136. slice_into(bci,b,ux);
  137. slice_into(bci,b,lx);
  138. bool r = mosek_quadprog(Q,c,0,A,lc,uc,lx,ux,data.mosek_data,Wi);
  139. if(!r)
  140. {
  141. return false;
  142. }
  143. W.col(i) = Wi;
  144. }
  145. break;
  146. }
  147. default:
  148. {
  149. assert(false && "Unknown qp_solver");
  150. return false;
  151. }
  152. }
  153. #ifndef NDEBUG
  154. const double min_rowsum = W.rowwise().sum().array().abs().minCoeff();
  155. if(min_rowsum < 0.1)
  156. {
  157. cerr<<"bbw.cpp: Warning, minimum row sum is very low. Consider more "
  158. "active set iterations or enforcing partition of unity."<<endl;
  159. }
  160. #endif
  161. }
  162. return true;
  163. }
  164. #ifndef IGL_HEADER_ONLY
  165. // Explicit template specialization
  166. template bool igl::bbw<Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, -1, 0, -1, -1>, Eigen::Matrix<int, -1, 1, 0, -1, 1>, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, -1, 0, -1, -1> >(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<int, -1, 1, 0, -1, 1> > const&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> > const&, igl::BBWData&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
  167. #endif