bbw.cpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201
  1. // This file is part of libigl, a simple c++ geometry processing library.
  2. //
  3. // Copyright (C) 2013 Alec Jacobson <alecjacobson@gmail.com>
  4. //
  5. // This Source Code Form is subject to the terms of the Mozilla Public License
  6. // v. 2.0. If a copy of the MPL was not distributed with this file, You can
  7. // obtain one at http://mozilla.org/MPL/2.0/.
  8. #include "bbw.h"
  9. #include <igl/cotmatrix.h>
  10. #include <igl/massmatrix.h>
  11. #include <igl/invert_diag.h>
  12. #include <igl/speye.h>
  13. #include <igl/slice_into.h>
  14. #include <igl/min_quad_with_fixed.h>
  15. #include <Eigen/Sparse>
  16. #include <iostream>
  17. #include <cstdio>
  18. igl::bbw::BBWData::BBWData():
  19. partition_unity(false),
  20. W0(),
  21. #ifndef IGL_NO_MOSEK
  22. mosek_data(),
  23. #endif
  24. active_set_params(),
  25. qp_solver(QP_SOLVER_IGL_ACTIVE_SET),
  26. verbosity(0)
  27. {
  28. // We know that the Bilaplacian is positive semi-definite
  29. active_set_params.Auu_pd = true;
  30. }
  31. void igl::bbw::BBWData::print()
  32. {
  33. using namespace std;
  34. cout<<"partition_unity: "<<partition_unity<<endl;
  35. cout<<"W0=["<<endl<<W0<<endl<<"];"<<endl;
  36. cout<<"qp_solver: "<<QPSolverNames[qp_solver]<<endl;
  37. }
  38. template <
  39. typename DerivedV,
  40. typename DerivedEle,
  41. typename Derivedb,
  42. typename Derivedbc,
  43. typename DerivedW>
  44. IGL_INLINE bool igl::bbw::bbw(
  45. const Eigen::PlainObjectBase<DerivedV> & V,
  46. const Eigen::PlainObjectBase<DerivedEle> & Ele,
  47. const Eigen::PlainObjectBase<Derivedb> & b,
  48. const Eigen::PlainObjectBase<Derivedbc> & bc,
  49. igl::bbw::BBWData & data,
  50. Eigen::PlainObjectBase<DerivedW> & W
  51. )
  52. {
  53. using namespace std;
  54. using namespace Eigen;
  55. // number of domain vertices
  56. int n = V.rows();
  57. // number of handles
  58. int m = bc.cols();
  59. // Build biharmonic operator
  60. SparseMatrix<typename DerivedW::Scalar> L;
  61. cotmatrix(V,Ele,L);
  62. SparseMatrix<typename DerivedW::Scalar> M;
  63. SparseMatrix<typename DerivedW::Scalar> Mi;
  64. massmatrix(V,Ele,MASSMATRIX_TYPE_DEFAULT,M);
  65. invert_diag(M,Mi);
  66. SparseMatrix<typename DerivedW::Scalar> Q = L.transpose() * Mi * L;
  67. assert(!data.partition_unity && "partition_unity not implemented yet");
  68. W.derived().resize(n,m);
  69. {
  70. // No linear terms
  71. VectorXd c = VectorXd::Zero(n);
  72. // No linear constraints
  73. SparseMatrix<typename DerivedW::Scalar> A(0,n),Aeq(0,n),Aieq(0,n);
  74. VectorXd uc(0,1),Beq(0,1),Bieq(0,1),lc(0,1);
  75. // Upper and lower box constraints (Constant bounds)
  76. VectorXd ux = VectorXd::Ones(n);
  77. VectorXd lx = VectorXd::Zero(n);
  78. active_set_params eff_params = data.active_set_params;
  79. switch(data.qp_solver)
  80. {
  81. case QP_SOLVER_IGL_ACTIVE_SET:
  82. {
  83. if(data.verbosity >= 1)
  84. {
  85. cout<<"BBW: max_iter: "<<data.active_set_params.max_iter<<endl;
  86. cout<<"BBW: eff_max_iter: "<<eff_params.max_iter<<endl;
  87. }
  88. if(data.verbosity >= 1)
  89. {
  90. cout<<"BBW: Computing initial weights for "<<m<<" handle"<<
  91. (m!=1?"s":"")<<"."<<endl;
  92. }
  93. min_quad_with_fixed_data<typename DerivedW::Scalar > mqwf;
  94. min_quad_with_fixed_precompute(Q,b,Aeq,true,mqwf);
  95. min_quad_with_fixed_solve(mqwf,c,bc,Beq,W);
  96. // decrement
  97. eff_params.max_iter--;
  98. bool error = false;
  99. // Loop over handles
  100. #pragma omp parallel for
  101. for(int i = 0;i<m;i++)
  102. {
  103. // Quicker exit for openmp
  104. if(error)
  105. {
  106. continue;
  107. }
  108. if(data.verbosity >= 1)
  109. {
  110. #pragma omp critical
  111. cout<<"BBW: Computing weight for handle "<<i+1<<" out of "<<m<<
  112. "."<<endl;
  113. }
  114. VectorXd bci = bc.col(i);
  115. VectorXd Wi;
  116. // use initial guess
  117. Wi = W.col(i);
  118. SolverStatus ret = active_set(
  119. Q,c,b,bci,Aeq,Beq,Aieq,Bieq,lx,ux,eff_params,Wi);
  120. switch(ret)
  121. {
  122. case SOLVER_STATUS_CONVERGED:
  123. break;
  124. case SOLVER_STATUS_MAX_ITER:
  125. cerr<<"active_set: max iter without convergence."<<endl;
  126. break;
  127. case SOLVER_STATUS_ERROR:
  128. default:
  129. cerr<<"active_set error."<<endl;
  130. error = true;
  131. }
  132. W.col(i) = Wi;
  133. }
  134. if(error)
  135. {
  136. return false;
  137. }
  138. break;
  139. }
  140. case QP_SOLVER_MOSEK:
  141. {
  142. #ifdef IGL_NO_MOSEK
  143. assert(false && "Use another QPSolver. Recompile without IGL_NO_MOSEK defined.");
  144. cerr<<"Use another QPSolver. Recompile without IGL_NO_MOSEK defined."<<endl;
  145. return false;
  146. #else
  147. // Loop over handles
  148. for(int i = 0;i<m;i++)
  149. {
  150. if(data.verbosity >= 1)
  151. {
  152. cout<<"BBW: Computing weight for handle "<<i+1<<" out of "<<m<<
  153. "."<<endl;
  154. }
  155. VectorXd bci = bc.col(i);
  156. VectorXd Wi;
  157. // impose boundary conditions via bounds
  158. slice_into(bci,b,ux);
  159. slice_into(bci,b,lx);
  160. bool r = mosek_quadprog(Q,c,0,A,lc,uc,lx,ux,data.mosek_data,Wi);
  161. if(!r)
  162. {
  163. return false;
  164. }
  165. W.col(i) = Wi;
  166. }
  167. #endif
  168. break;
  169. }
  170. default:
  171. {
  172. assert(false && "Unknown qp_solver");
  173. return false;
  174. }
  175. }
  176. #ifndef NDEBUG
  177. const double min_rowsum = W.rowwise().sum().array().abs().minCoeff();
  178. if(min_rowsum < 0.1)
  179. {
  180. cerr<<"bbw.cpp: Warning, minimum row sum is very low. Consider more "
  181. "active set iterations or enforcing partition of unity."<<endl;
  182. }
  183. #endif
  184. }
  185. return true;
  186. }
  187. #ifdef IGL_STATIC_LIBRARY
  188. // Explicit template specialization
  189. template bool igl::bbw::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::bbw::BBWData&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&);
  190. #endif