eigs.cpp 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. #include "eigs.h"
  2. #include "read_triangle_mesh.h"
  3. #include "cotmatrix.h"
  4. #include "sort.h"
  5. #include "slice.h"
  6. #include "massmatrix.h"
  7. #include <iostream>
  8. template <
  9. typename Atype,
  10. typename Btype,
  11. typename DerivedU,
  12. typename DerivedS>
  13. IGL_INLINE bool igl::eigs(
  14. const Eigen::SparseMatrix<Atype> & A,
  15. const Eigen::SparseMatrix<Btype> & iB,
  16. const size_t k,
  17. const EigsType type,
  18. Eigen::PlainObjectBase<DerivedU> & sU,
  19. Eigen::PlainObjectBase<DerivedS> & sS)
  20. {
  21. using namespace Eigen;
  22. using namespace std;
  23. const size_t n = A.rows();
  24. assert(A.cols() == n && "A should be square.");
  25. assert(iB.rows() == n && "B should be match A's dims.");
  26. assert(iB.cols() == n && "B should be square.");
  27. assert(type == EIGS_TYPE_SM && "Only low frequencies are supported");
  28. DerivedU U(n,k);
  29. DerivedS S(k,1);
  30. typedef Atype Scalar;
  31. typedef Eigen::Matrix<typename DerivedU::Scalar,DerivedU::RowsAtCompileTime,1> VectorXS;
  32. // Rescale B for better numerics
  33. const Scalar rescale = std::abs(iB.diagonal().maxCoeff());
  34. const Eigen::SparseMatrix<Btype> B = iB/rescale;
  35. Scalar tol = 1e-4;
  36. Scalar conv = 1e-14;
  37. int max_iter = 100;
  38. int i = 0;
  39. while(true)
  40. {
  41. // Random initial guess
  42. VectorXS y = VectorXS::Random(n,1);
  43. Scalar eff_sigma = 0;
  44. if(i>0)
  45. {
  46. eff_sigma = 1e-8+std::abs(S(i-1));
  47. }
  48. // whether to use rayleigh quotient method
  49. bool ray = false;
  50. Scalar err = std::numeric_limits<Scalar>::infinity();
  51. int iter;
  52. Scalar sigma = std::numeric_limits<Scalar>::infinity();
  53. VectorXS x;
  54. for(iter = 0;iter<max_iter;iter++)
  55. {
  56. if(i>0 && !ray)
  57. {
  58. // project-out existing modes
  59. for(int j = 0;j<i;j++)
  60. {
  61. const VectorXS u = U.col(j);
  62. y = (y - u*u.dot(B*y)/u.dot(B * u)).eval();
  63. }
  64. }
  65. // normalize
  66. x = y/sqrt(y.dot(B*y));
  67. // current guess at eigen value
  68. sigma = x.dot(A*x)/x.dot(B*x);
  69. //x *= sigma>0?1.:-1.;
  70. Scalar err_prev = err;
  71. err = (A*x-sigma*B*x).array().abs().maxCoeff();
  72. if(err<conv)
  73. {
  74. break;
  75. }
  76. if(ray || err<tol)
  77. {
  78. eff_sigma = sigma;
  79. ray = true;
  80. }
  81. Scalar tikhonov = std::abs(eff_sigma)<1e-12?1e-10:0;
  82. switch(type)
  83. {
  84. default:
  85. assert(false && "Not supported");
  86. break;
  87. case EIGS_TYPE_SM:
  88. {
  89. SimplicialLDLT<SparseMatrix<Scalar> > solver;
  90. const SparseMatrix<Scalar> C = A-eff_sigma*B+tikhonov*B;
  91. //mw.save(C,"C");
  92. //mw.save(eff_sigma,"eff_sigma");
  93. //mw.save(tikhonov,"tikhonov");
  94. solver.compute(C);
  95. switch(solver.info())
  96. {
  97. case Eigen::Success:
  98. break;
  99. case Eigen::NumericalIssue:
  100. cerr<<"Error: Numerical issue."<<endl;
  101. return false;
  102. default:
  103. cerr<<"Error: Other."<<endl;
  104. return false;
  105. }
  106. const VectorXS rhs = B*x;
  107. y = solver.solve(rhs);
  108. //mw.save(rhs,"rhs");
  109. //mw.save(y,"y");
  110. //mw.save(x,"x");
  111. //mw.write("eigs.mat");
  112. //if(i == 1)
  113. //return false;
  114. break;
  115. }
  116. }
  117. }
  118. if(iter == max_iter)
  119. {
  120. cerr<<"Failed to converge."<<endl;
  121. return false;
  122. }
  123. if(i==0 || (S.head(i).array()-sigma).abs().maxCoeff()>1e-14)
  124. {
  125. U.col(i) = x;
  126. S(i) = sigma;
  127. i++;
  128. if(i == k)
  129. {
  130. break;
  131. }
  132. }else
  133. {
  134. // restart with new random guess.
  135. cout<<"RESTART!"<<endl;
  136. }
  137. }
  138. // finally sort
  139. VectorXi I;
  140. igl::sort(S,1,false,sS,I);
  141. sU = igl::slice(U,I,2);
  142. sS /= rescale;
  143. sU /= sqrt(rescale);
  144. return true;
  145. }
  146. #ifdef IGL_STATIC_LIBRARY
  147. // Explicit template specialization
  148. template bool igl::eigs<double, double, Eigen::Matrix<double, -1, -1, 0, -1, -1>, Eigen::Matrix<double, -1, 1, 0, -1, 1> >(Eigen::SparseMatrix<double, 0, int> const&, Eigen::SparseMatrix<double, 0, int> const&, unsigned long, igl::EigsType, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, -1, 0, -1, -1> >&, Eigen::PlainObjectBase<Eigen::Matrix<double, -1, 1, 0, -1, 1> >&);
  149. #endif