core/vnl/algo/vnl_generalized_eigensystem.cxx
Go to the documentation of this file.
00001 // This is core/vnl/algo/vnl_generalized_eigensystem.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //
00006 // vnl_generalized_eigensystem
00007 // Author: Andrew W. Fitzgibbon, Oxford RRG
00008 // Created: 29 Aug 96
00009 //
00010 
00011 #include "vnl_generalized_eigensystem.h"
00012 
00013 #include <vcl_iostream.h>
00014 #ifdef VCL_SGI_CC_730
00015 # include <vcl_cmath.h>
00016 #endif
00017 
00018 #include <vnl/vnl_fortran_copy.h>
00019 #include <vnl/vnl_matlab_print.h>
00020 #include <vnl/algo/vnl_symmetric_eigensystem.h>
00021 #include <vnl/algo/vnl_svd.h>
00022 #include <vnl/algo/vnl_netlib.h> // rsg_()
00023 
00024 vnl_generalized_eigensystem::vnl_generalized_eigensystem(const vnl_matrix<double>& A,
00025                                                          const vnl_matrix<double>& B)
00026   :
00027   n(A.rows()), V(n,n), D(n)
00028 {
00029   // Copy source matrices into fortran storage
00030   vnl_fortran_copy<double> a(A);
00031   vnl_fortran_copy<double> b(B);
00032 
00033   // Make workspace and storage for V transpose
00034   vnl_vector<double> work1(n);
00035   vnl_vector<double> work2(n);
00036   vnl_vector<double> V1(n*n);
00037 
00038   long want_eigenvectors = 1;
00039   long ierr = -1;
00040 
00041   // Call EISPACK rsg.
00042   v3p_netlib_rsg_ (&n, &n, a, b, D.data_block(),
00043                    &want_eigenvectors,
00044                    V1.begin(),
00045                    work1.begin(),
00046                    work2.begin(), &ierr);
00047 
00048   // If b was not pos-def, retry with projection onto nullspace
00049   if (ierr == 7*n+1) {
00050     const double THRESH = 1e-8;
00051     vnl_symmetric_eigensystem<double> eig(B);
00052     if (eig.D(0,0) < -THRESH) {
00053       vcl_cerr << "**** vnl_generalized_eigensystem: ERROR\n"
00054                << "Matrix B is not nonneg-definite\n";
00055       vnl_matlab_print(vcl_cerr, B, "B");
00056       vcl_cerr << "**** eigenvalues(B) = " << eig.D << vcl_endl;
00057       return;
00058     }
00059     // hmmmmm - all this crap below is worse than whatever the default is...
00060     return;
00061 #if 0 // so don't compile it then...
00062     int rank_deficiency = 0;
00063     while (eig.D(rank_deficiency,rank_deficiency) < THRESH)
00064       ++rank_deficiency;
00065     int rank = B.columns() - rank_deficiency;
00066 
00067     vcl_cerr << "vnl_generalized_eigensystem: B rank def by " << rank_deficiency << vcl_endl;
00068     // M is basis for non-nullspace of B
00069     vnl_matrix<double> M = eig.V.get_n_columns(rank_deficiency, rank);
00070     vnl_matrix<double> N = eig.V.get_n_columns(0, rank_deficiency);
00071 
00072     vnl_svd<double> svd(vnl_transpose(M)*A*N);
00073 
00074     vnl_generalized_eigensystem reduced(vnl_transpose(M) * A * M,
00075                                         vnl_transpose(M) * B * M);
00076 
00077     vcl_cerr << "AN: " << reduced.D << vcl_endl;
00078 
00079     vnl_matrix<double> V05 = M * vnl_transpose(reduced.V);
00080     vnl_svd<double> sv6(V05.transpose());
00081     V.update(V05, 0, 0);
00082     V.update(sv6.nullspace(), 0, rank - 1);
00083     for (int i = 0; i < rank; ++i)
00084       D(i,i) = reduced.D(i,i);
00085     for (unsigned i = rank; i < B.columns(); ++i)
00086       D(i,i) = 0;
00087     vcl_cerr << "AN: " << D << vcl_endl;
00088 
00089     return;
00090 #endif
00091   }
00092 
00093   // transpose-copy V1 to V
00094   {
00095     double *vptr = &V1[0];
00096     for (int c = 0; c < n; ++c)
00097       for (int r = 0; r < n; ++r)
00098         V(r,c) = *vptr++;
00099   }
00100 
00101   // Diagnose errors
00102   if (ierr) {
00103     if (ierr == 10*n)
00104       vcl_cerr << "vnl_generalized_eigensystem: N is greater than NM.  Bug in interface to rsg.f\n";
00105     else {
00106       vcl_cerr << "vnl_generalized_eigensystem: The "
00107                << ierr << "-th eigenvalue has not been determined after 30 iterations.\n"
00108                << "The eigenvalues should be correct for indices 1.." << ierr-1
00109                << ", but no eigenvectors are computed.\n"
00110                << "A = " << A
00111                << "\nsingular values(A) = " << vnl_svd<double>(A).W() << '\n'
00112                << "B = " << B
00113                << "\nsingular values(B) = " << vnl_svd<double>(B).W() << '\n';
00114     }
00115   }
00116 }