bbw.cpp 6.2 KB

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