ILSMinResLanczos.cpp 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212
  1. /**
  2. * @file ILSMinResLanczos.cpp
  3. * @brief Iteratively solving linear equation systems with the minimum residual (MINRES) method using Lanczos process
  4. * @author Paul Bodesheim
  5. * @date 20/01/2012 (dd/mm/yyyy)
  6. */
  7. #include <iostream>
  8. #include "ILSMinResLanczos.h"
  9. using namespace NICE;
  10. using namespace std;
  11. ILSMinResLanczos::ILSMinResLanczos( bool verbose, uint maxIterations, double minDelta) //, bool useFlexibleVersion )
  12. {
  13. this->minDelta = minDelta;
  14. this->maxIterations = maxIterations;
  15. this->verbose = verbose;
  16. // this->useFlexibleVersion = useFlexibleVersion;
  17. }
  18. ILSMinResLanczos::~ILSMinResLanczos()
  19. {
  20. }
  21. // void ILSMinResLanczos::setJacobiPreconditionerLanczos ( const Vector & jacobiPreconditioner )
  22. // {
  23. // this->jacobiPreconditioner = jacobiPreconditioner;
  24. // }
  25. int ILSMinResLanczos::solveLin ( const GenericMatrix & gm, const Vector & b, Vector & x )
  26. {
  27. if ( b.size() != gm.rows() ) {
  28. fthrow(Exception, "Size of vector b (" << b.size() << ") mismatches with the size of the given GenericMatrix (" << gm.rows() << ").");
  29. }
  30. if ( x.size() != gm.cols() )
  31. {
  32. x.resize(gm.cols());
  33. x.set(0.0); // bad initial solution, but whatever
  34. }
  35. // if ( verbose ) cerr << "initial solution: " << x << endl;
  36. // MINRES-Method based on Lanczos vectors: implementation based on the following:
  37. //
  38. // C.C. Paige and M.A. Saunders: "Solution of sparse indefinite systems of linear equations". SIAM Journal on Numerical Analysis, p. 617--629, vol. 12, no. 4, 1975
  39. //
  40. // http://www.netlib.org/templates/templates.pdf
  41. //
  42. // declare some helpers
  43. double gamma = 0.0;
  44. double gamma_bar = 0.0;
  45. double alpha = 0.0; // alpha_j = v_j^T * A * v_j for new Lanczos vector v_j
  46. double beta = b.normL2(); // beta_1 = norm(b), in general beta_j = norm(v_j) for new Lanczos vector v_j
  47. double beta_next = 0.0; // beta_{j+1}
  48. double c_new = 0.0;
  49. double c_old = -1.0;
  50. double s_new = 0.0;
  51. double s_old = 0.0;
  52. double delta_new = 0.0;
  53. double epsilon_next = 0.0;
  54. double t_new = 0.0;
  55. // init some helping vectors
  56. Vector Av(b.size(),0.0); // Av = A * v_j
  57. Vector Ac(b.size(),0.0); // Ac = A * c_j
  58. Vector *v_new = new Vector(b.size(),0.0); // new Lanczos vector v_j
  59. Vector *v_old = 0; // Lanczos vector of the iteration before: v_{j-1}
  60. Vector *v_next = new Vector(b.size(),0.0); // Lanczos vector of the next iteration: v_{j+1}
  61. Vector *m_new = new Vector(x.size(),0.0); // current update vector m_j for the solution x
  62. Vector *m_old = new Vector(x.size(),0.0); // update vector m_{j-1} of iteration before
  63. Vector *m_older = 0; // update vector m_{j-2} of iteration before
  64. // first iteration + initialization, where b will be used as the first Lanczos vector
  65. *v_new = (1/beta)*b; // init v_1, v_1 = b / norm(b)
  66. gm.multiply(Av,*v_new); // Av = A * v_1
  67. alpha = v_new->scalarProduct(Av); // alpha_1 = v_1^T * A * v_1
  68. gamma_bar = alpha; // (gamma_bar_1 is equal to alpha_1 in ILSConjugateGradientsLanczos)
  69. *v_next = Av - (alpha*(*v_new));
  70. beta_next = v_next->normL2();
  71. v_next->normalizeL2();
  72. // calculate helpers (equation 5.6 in the paper mentioned above)
  73. gamma = sqrt( (gamma_bar*gamma_bar) + (beta_next*beta_next) );
  74. c_new = gamma_bar/gamma;
  75. s_new = beta_next/gamma;
  76. t_new = beta*c_new; // t_1 = beta_1 * c_1
  77. *m_new = (1/gamma)*(*v_new); // m_1 = ( 1 / gamma_1 ) * v_1
  78. x = t_new*(*m_new); // first approximation of x
  79. // calculate current residual of x
  80. double res = (beta*beta)*(s_new*s_new);
  81. // calculate delta of x_L
  82. double delta_x = fabs(t_new) * m_new->normL2();
  83. if ( verbose ) {
  84. cerr << "ILSMinResLanczos: iteration 1 / " << maxIterations << endl;
  85. if ( x.size() <= 20 )
  86. cerr << "ILSMinResLanczos: current solution x: " << x << endl;
  87. cerr << "ILSMinResLanczos: delta_x = " << delta_x << endl;
  88. }
  89. // start with second iteration
  90. uint j = 2;
  91. while (j <= maxIterations )
  92. {
  93. // prepare next iteration
  94. if ( v_old == 0 ) v_old = v_new;
  95. else {
  96. delete v_old;
  97. v_old = v_new;
  98. }
  99. v_new = v_next;
  100. v_next = new Vector(b.size(),0.0);
  101. if ( m_older == 0 ) m_older = m_old;
  102. else {
  103. delete m_older;
  104. m_older = m_old;
  105. }
  106. m_old = m_new;
  107. m_new = new Vector(x.size(),0.0);
  108. beta = beta_next;
  109. s_old = s_new;
  110. t_new /= c_new;
  111. // start next iteration:
  112. // calculate next Lanczos vector v_ {j+1} based on older ones
  113. gm.multiply(Av,*v_new);
  114. alpha = v_new->scalarProduct(Av);
  115. *v_next = Av - (alpha*(*v_new)) - (beta*(*v_old)); // calculate v_{j+1}
  116. beta_next = v_next->normL2(); // calculate beta_{j+1}
  117. v_next->normalizeL2(); // normalize v_{j+1}
  118. // calculate elements of matrix L_bar_{j}
  119. gamma_bar = -c_old*s_new*beta - c_new*alpha; // calculate gamma_bar_{j}
  120. delta_new = -c_old*c_new*beta + s_new*alpha; // calculate delta_{j}
  121. //NOTE updating c_old after using it to calculate gamma_bar and delta_new is important!!
  122. c_old = c_new;
  123. // calculate helpers (equation 5.6 in the paper mentioned above)
  124. gamma = sqrt( (gamma_bar*gamma_bar) + (beta_next*beta_next) ); // calculate gamma_{j}
  125. c_new = gamma_bar/gamma; // calculate c_{j-1}
  126. s_new = beta_next/gamma; // calculate s_{j-1}
  127. // calculate t_{j} according to equation 6.7 of the paper mentioned above
  128. t_new *= s_old*c_new;
  129. // calculate m_{j}
  130. *m_new = (1/gamma)*(*v_new - (delta_new*(*m_old)) - (epsilon_next*(*m_older)) );
  131. epsilon_next = s_old*beta_next; // calculate epsilon_{j+1} of matrix L_bar_{j+1}
  132. x += t_new*(*m_new); // update x
  133. // calculate residual of current solution x
  134. res *= (s_new*s_new);
  135. if ( verbose ) {
  136. cerr << "ILSMinResLanczos: iteration " << j << " / " << maxIterations << endl;
  137. if ( x.size() <= 20 )
  138. {
  139. cerr << "ILSMinResLanczos: current solution x: " << x << endl;
  140. }
  141. }
  142. // check convergence
  143. delta_x = fabs(t_new) * m_new->normL2();
  144. if ( verbose ) {
  145. cerr << "ILSMinResLanczos: delta_x = " << delta_x << endl;
  146. cerr << "ILSMinResLanczos: residual = " << res << endl;
  147. }
  148. if ( delta_x < minDelta ) {
  149. if ( verbose )
  150. cerr << "ILSMinResLanczos: small delta_x" << endl;
  151. break;
  152. }
  153. j++;
  154. }
  155. // Normally, we do not need this, because the last iteration produces the optimal solution with minimal residual.
  156. // However, we will have this outputs equally to the other ILS methods.
  157. // if ( verbose ) {
  158. cerr << "ILSMinResLanczos: iterations needed: " << std::min<uint>(j,maxIterations) << endl;
  159. cerr << "ILSMinResLanczos: minimal residual achieved: " << res << endl;
  160. if ( x.size() <= 20 )
  161. cerr << "ILSMinResLanczos: optimal solution: " << x << endl;
  162. // }
  163. delete v_new;
  164. delete v_old;
  165. delete v_next;
  166. delete m_new;
  167. delete m_old;
  168. delete m_older;
  169. return 0;
  170. }