eigs.cpp 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145
  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> & B,
  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(B.rows() == n && "B should be match A's dims.");
  26. assert(B.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. Scalar tol = 1e-4;
  33. Scalar conv = 1e-15;
  34. int max_iter = 100;
  35. int i = 0;
  36. while(true)
  37. {
  38. // Random initial guess
  39. VectorXS y = VectorXS::Random(n,1);
  40. Scalar eff_sigma = 0;
  41. if(i>0)
  42. {
  43. eff_sigma = 1e-8+std::abs(S(i-1));
  44. }
  45. // whether to use rayleigh quotient method
  46. bool ray = false;
  47. Scalar err = std::numeric_limits<Scalar>::infinity();
  48. int iter;
  49. Scalar sigma = std::numeric_limits<Scalar>::infinity();
  50. VectorXS x;
  51. for(iter = 0;iter<max_iter;iter++)
  52. {
  53. if(i>0 && !ray)
  54. {
  55. // project-out existing modes
  56. for(int j = 0;j<i;j++)
  57. {
  58. const VectorXS u = U.col(j);
  59. y = (y - u*u.dot(B*y)/u.dot(B * u)).eval();
  60. }
  61. }
  62. // normalize
  63. x = y/sqrt(y.dot(B*y));
  64. // current guess at eigen value
  65. sigma = x.dot(A*x)/x.dot(B*x);
  66. //x *= sigma>0?1.:-1.;
  67. Scalar err_prev = err;
  68. err = (A*x-sigma*B*x).array().abs().maxCoeff();
  69. if(err<conv)
  70. {
  71. break;
  72. }
  73. if(ray || err<tol)
  74. {
  75. eff_sigma = sigma;
  76. ray = true;
  77. }
  78. Scalar tikhonov = std::abs(eff_sigma)<1e-12?1e-10:0;
  79. switch(type)
  80. {
  81. default:
  82. assert(false && "Not supported");
  83. break;
  84. case EIGS_TYPE_SM:
  85. {
  86. SimplicialLDLT<SparseMatrix<Scalar> > solver;
  87. const SparseMatrix<Scalar> C = A-eff_sigma*B+tikhonov*B;
  88. //mw.save(C,"C");
  89. //mw.save(eff_sigma,"eff_sigma");
  90. //mw.save(tikhonov,"tikhonov");
  91. solver.compute(C);
  92. switch(solver.info())
  93. {
  94. case Eigen::Success:
  95. break;
  96. case Eigen::NumericalIssue:
  97. cerr<<"Error: Numerical issue."<<endl;
  98. return false;
  99. default:
  100. cerr<<"Error: Other."<<endl;
  101. return false;
  102. }
  103. const VectorXS rhs = B*x;
  104. y = solver.solve(rhs);
  105. //mw.save(rhs,"rhs");
  106. //mw.save(y,"y");
  107. //mw.save(x,"x");
  108. //mw.write("eigs.mat");
  109. //if(i == 1)
  110. //return false;
  111. break;
  112. }
  113. }
  114. }
  115. if(iter == max_iter)
  116. {
  117. cerr<<"Failed to converge."<<endl;
  118. return false;
  119. }
  120. if(i==0 || (S.head(i).array()-sigma).abs().maxCoeff()>1e-14)
  121. {
  122. U.col(i) = x;
  123. S(i) = sigma;
  124. i++;
  125. if(i == k)
  126. {
  127. break;
  128. }
  129. }else
  130. {
  131. // restart with new random guess.
  132. cout<<"RESTART!"<<endl;
  133. }
  134. }
  135. // finally sort
  136. VectorXi I;
  137. igl::sort(S,1,false,sS,I);
  138. sU = igl::slice(U,I,2);
  139. return true;
  140. }