EigValues.cpp 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /**
  2. * @file EigValues.cpp
  3. * @brief EigValues Class
  4. * @author Michael Koch
  5. * @date 08/19/2008
  6. */
  7. #include <iostream>
  8. #include "EigValues.h"
  9. #define DEBUG_ARNOLDI
  10. using namespace NICE;
  11. using namespace std;
  12. void
  13. EVArnoldi::getEigenvalues ( const GenericMatrix & data, Vector & eigenvalues,
  14. Matrix & eigenvectors, uint k )
  15. {
  16. /////////////////////////////////////
  17. ///////// check input arguments /////
  18. /////////////////////////////////////
  19. if ( data.rows () != data.cols () )
  20. {
  21. throw ( "EVArnoldi: matrix has to be quadratic" );
  22. }
  23. if ( k <= 0 )
  24. {
  25. throw ( "EVArnoldi: please use k>0." );
  26. }
  27. // did we specify more eigenvalues than the matrix can actually have?
  28. if ( k > data.rows() )
  29. {
  30. throw ( "EVArnoldi: specified k is larger then dimension of matrix! Aborting..." );
  31. }
  32. //////////////////////////////////////
  33. ///////// initialize variables ///////
  34. //////////////////////////////////////
  35. if ( verbose )
  36. cerr << "Initialize Matrices" << std::endl;
  37. uint n = data.cols ();
  38. if ( verbose )
  39. std::cerr << "EVArnoldi: n: " << n << " k: " << k << std::endl;
  40. NICE::Matrix rmatrix ( n, k, 0 ); //=eigenvectors
  41. NICE::Matrix qmatrix ( n, k, 0 ); //saves data =eigenvectors
  42. eigenvalues.resize ( k );
  43. NICE::Vector q ( n );
  44. NICE::Vector r ( n );
  45. if ( verbose )
  46. cerr << "Random Initialization" << endl;
  47. //random initialisation
  48. for ( uint i = 0; i < k; i++ )
  49. for ( uint j = 0; j < n; j++ )
  50. #ifdef WIN32
  51. rmatrix (j, i) = double(rand())/RAND_MAX;
  52. #else
  53. rmatrix (j, i) = drand48 ();
  54. #endif
  55. // rmatrix ( j, i ) = 0.5;
  56. //TODO the random initialization might help, but it is bad for reproducibility :(
  57. ////////////////////////////////////
  58. ///////// start computation ///////
  59. ////////////////////////////////////
  60. if ( verbose )
  61. std::cerr << "EVArnoldi: start main computation" << std::endl;
  62. //reduceddim
  63. double delta = 1.0;
  64. uint iteration = 0;
  65. while ( delta > mindelta && iteration < maxiterations )
  66. {
  67. //replace Vector rold by matrix rold to check for convergence of all eigenvectors
  68. //NICE::Vector rold ( rmatrix.getColumn ( k - 1 ) );
  69. NICE::Matrix rold(rmatrix);
  70. if ( verbose )
  71. std::cerr << "EVArnoldi: start for loop over reduced dims" << std::endl;
  72. // meta-comment: i is an index for the iteration, j is an index for the basis
  73. // element (1 <= j <= k)
  74. for ( uint reduceddim = 0; reduceddim < k; reduceddim++ )
  75. {
  76. // -> get r^i_j from R matrix
  77. q = rmatrix.getColumn ( reduceddim );
  78. // q^i_j = r^i_j / ||r^i_j||
  79. q.normalizeL2 ();
  80. // -> store in Q matrix
  81. qmatrix.getColumnRef ( reduceddim ) = q;
  82. // this line copies a vector with external memory!
  83. // changing currentcol leads to a change in the R matrix!!
  84. Vector currentCol = rmatrix.getColumnRef ( reduceddim );
  85. // r^{i+1}_j = A * q^i_j ( r^i_j is overwritten by r^{i+1}_j )
  86. data.multiply ( currentCol, q );
  87. // for all j: r^{i+1}_j -= q^i_j * < q^i_j, r^{i+1}_j >
  88. for ( uint j = 0; j < reduceddim; j++ )
  89. rmatrix.getColumnRef ( reduceddim ) -=
  90. qmatrix.getColumn ( j ) *
  91. ( qmatrix.getColumn ( j ).
  92. scalarProduct ( rmatrix.getColumn ( reduceddim ) ) );
  93. }
  94. if ( verbose )
  95. std::cerr << "EVArnoldi: ended for loop over reduced dims" << std::endl;
  96. //convergence stuff (replaced by checking all eigenvectors instead of a single one
  97. //NICE::Vector diff = rold - rmatrix.getColumn ( k - 1 );
  98. //delta = diff.normL2 ();
  99. NICE::Vector tmpDiff;
  100. double norm_tmpDiff;
  101. delta = 0.0;
  102. for ( uint j = 0; j < k; j++ )
  103. {
  104. tmpDiff = rold.getColumn(j) - rmatrix.getColumn(j);
  105. norm_tmpDiff = tmpDiff.normL2();
  106. if (norm_tmpDiff > delta)
  107. delta = norm_tmpDiff;
  108. }
  109. iteration++;
  110. if ( verbose )
  111. cerr << "EVArnoldi: [" << iteration << "] delta=" << delta << endl;
  112. }
  113. if ( verbose )
  114. std::cerr << "EVArnoldi: while-loop done" << std::endl;
  115. eigenvectors = rmatrix;
  116. for ( uint i = 0; i < k; i++ )
  117. {
  118. NICE::Vector tmp;
  119. eigenvectors.getColumnRef ( i ).normalizeL2 ();
  120. data.multiply ( tmp, eigenvectors.getColumn ( i ) );
  121. eigenvalues[i] = tmp.scalarProduct ( eigenvectors.getColumn ( i ) );
  122. }
  123. // post-processing: ensure that eigenvalues are in correct order!
  124. if ( this->b_verifyDecreasingOrder && (k > 1) )
  125. {
  126. NICE::VectorT< int > ewPermutation;
  127. eigenvalues.sortDescend ( ewPermutation );
  128. NICE::Vector tmpRow;
  129. int tmpIdx (-1);
  130. for ( uint i = 0; i < k; i++ )
  131. {
  132. if ( i == ewPermutation[i] )
  133. {
  134. //identity - nothing to do here
  135. }
  136. else
  137. {
  138. if ( tmpIdx == -1 )
  139. {
  140. tmpIdx = i;
  141. tmpRow = eigenvectors.getColumn ( i );
  142. eigenvectors.getColumnRef ( i ) = eigenvectors.getColumn ( ewPermutation[i] );
  143. }
  144. else
  145. {
  146. if ( tmpIdx != ewPermutation[i] )
  147. {
  148. eigenvectors.getColumnRef ( i ) = eigenvectors.getColumn ( ewPermutation[i] );
  149. }
  150. else // tmpIdx == ewPermutation[i]
  151. {
  152. eigenvectors.getColumnRef ( i ) = tmpRow;
  153. tmpIdx = -1;
  154. }
  155. }
  156. }
  157. }
  158. }// sorting is only useful if we compute more then 1 ew
  159. }