123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191 |
- /**
- * @file EigValues.cpp
- * @brief EigValues Class
- * @author Michael Koch
- * @date 08/19/2008
- */
- #include <iostream>
- #include "EigValues.h"
- #define DEBUG_ARNOLDI
- using namespace NICE;
- using namespace std;
- void
- EVArnoldi::getEigenvalues ( const GenericMatrix & data, Vector & eigenvalues,
- Matrix & eigenvectors, uint k )
- {
- /////////////////////////////////////
- ///////// check input arguments /////
- /////////////////////////////////////
- if ( data.rows () != data.cols () )
- {
- throw ( "EVArnoldi: matrix has to be quadratic" );
- }
-
- if ( k <= 0 )
- {
- throw ( "EVArnoldi: please use k>0." );
- }
-
- // did we specify more eigenvalues than the matrix can actually have?
- if ( k > data.rows() )
- {
- throw ( "EVArnoldi: specified k is larger then dimension of matrix! Aborting..." );
- }
-
- //////////////////////////////////////
- ///////// initialize variables ///////
- //////////////////////////////////////
- if ( verbose )
- cerr << "Initialize Matrices" << std::endl;
- uint n = data.cols ();
-
- if ( verbose )
- std::cerr << "EVArnoldi: n: " << n << " k: " << k << std::endl;
-
- NICE::Matrix rmatrix ( n, k, 0 ); //=eigenvectors
- NICE::Matrix qmatrix ( n, k, 0 ); //saves data =eigenvectors
- eigenvalues.resize ( k );
- NICE::Vector q ( n );
- NICE::Vector r ( n );
- if ( verbose )
- cerr << "Random Initialization" << endl;
- //random initialisation
- for ( uint i = 0; i < k; i++ )
- for ( uint j = 0; j < n; j++ )
- #ifdef WIN32
- rmatrix (j, i) = double(rand())/RAND_MAX;
- #else
- rmatrix (j, i) = drand48 ();
- #endif
- // rmatrix ( j, i ) = 0.5;
- //TODO the random initialization might help, but it is bad for reproducibility :(
- ////////////////////////////////////
- ///////// start computation ///////
- ////////////////////////////////////
- if ( verbose )
- std::cerr << "EVArnoldi: start main computation" << std::endl;
-
- //reduceddim
- double delta = 1.0;
- uint iteration = 0;
- while ( delta > mindelta && iteration < maxiterations )
- {
- //replace Vector rold by matrix rold to check for convergence of all eigenvectors
- //NICE::Vector rold ( rmatrix.getColumn ( k - 1 ) );
- NICE::Matrix rold(rmatrix);
-
- if ( verbose )
- std::cerr << "EVArnoldi: start for loop over reduced dims" << std::endl;
-
- // meta-comment: i is an index for the iteration, j is an index for the basis
- // element (1 <= j <= k)
- for ( uint reduceddim = 0; reduceddim < k; reduceddim++ )
- {
- // -> get r^i_j from R matrix
- q = rmatrix.getColumn ( reduceddim );
- // q^i_j = r^i_j / ||r^i_j||
- q.normalizeL2 ();
- // -> store in Q matrix
- qmatrix.getColumnRef ( reduceddim ) = q;
- // this line copies a vector with external memory!
- // changing currentcol leads to a change in the R matrix!!
- Vector currentCol = rmatrix.getColumnRef ( reduceddim );
- // r^{i+1}_j = A * q^i_j ( r^i_j is overwritten by r^{i+1}_j )
- data.multiply ( currentCol, q );
- // for all j: r^{i+1}_j -= q^i_j * < q^i_j, r^{i+1}_j >
- for ( uint j = 0; j < reduceddim; j++ )
- rmatrix.getColumnRef ( reduceddim ) -=
- qmatrix.getColumn ( j ) *
- ( qmatrix.getColumn ( j ).
- scalarProduct ( rmatrix.getColumn ( reduceddim ) ) );
- }
-
- if ( verbose )
- std::cerr << "EVArnoldi: ended for loop over reduced dims" << std::endl;
-
- //convergence stuff (replaced by checking all eigenvectors instead of a single one
- //NICE::Vector diff = rold - rmatrix.getColumn ( k - 1 );
- //delta = diff.normL2 ();
- NICE::Vector tmpDiff;
- double norm_tmpDiff;
- delta = 0.0;
- for ( uint j = 0; j < k; j++ )
- {
- tmpDiff = rold.getColumn(j) - rmatrix.getColumn(j);
- norm_tmpDiff = tmpDiff.normL2();
- if (norm_tmpDiff > delta)
- delta = norm_tmpDiff;
- }
- iteration++;
- if ( verbose )
- cerr << "EVArnoldi: [" << iteration << "] delta=" << delta << endl;
- }
-
- if ( verbose )
- std::cerr << "EVArnoldi: while-loop done" << std::endl;
-
- eigenvectors = rmatrix;
-
- for ( uint i = 0; i < k; i++ )
- {
- NICE::Vector tmp;
- eigenvectors.getColumnRef ( i ).normalizeL2 ();
- data.multiply ( tmp, eigenvectors.getColumn ( i ) );
- eigenvalues[i] = tmp.scalarProduct ( eigenvectors.getColumn ( i ) );
- }
-
- // post-processing: ensure that eigenvalues are in correct order!
-
- if ( this->b_verifyDecreasingOrder && (k > 1) )
- {
- NICE::VectorT< int > ewPermutation;
- eigenvalues.sortDescend ( ewPermutation );
-
- NICE::Vector tmpRow;
- int tmpIdx (-1);
- for ( uint i = 0; i < k; i++ )
- {
- if ( i == ewPermutation[i] )
- {
- //identity - nothing to do here
- }
- else
- {
- if ( tmpIdx == -1 )
- {
- tmpIdx = i;
- tmpRow = eigenvectors.getColumn ( i );
- eigenvectors.getColumnRef ( i ) = eigenvectors.getColumn ( ewPermutation[i] );
- }
- else
- {
- if ( tmpIdx != ewPermutation[i] )
- {
- eigenvectors.getColumnRef ( i ) = eigenvectors.getColumn ( ewPermutation[i] );
- }
- else // tmpIdx == ewPermutation[i]
- {
- eigenvectors.getColumnRef ( i ) = tmpRow;
- tmpIdx = -1;
- }
- }
- }
- }
-
- }// sorting is only useful if we compute more then 1 ew
- }
|