core/vnl/algo/vnl_sparse_symmetric_eigensystem.cxx

Go to the documentation of this file.
00001 // This is core/vnl/algo/vnl_sparse_symmetric_eigensystem.cxx
00002 #ifdef VCL_NEEDS_PRAGMA_INTERFACE
00003 #pragma implementation
00004 #endif
00005 //:
00006 // \file
00007 
00008 #include "vnl_sparse_symmetric_eigensystem.h"
00009 #include <vcl_cassert.h>
00010 #include <vcl_cstring.h>
00011 #include <vcl_iostream.h>
00012 #include <vcl_vector.h>
00013 
00014 #include <vnl/algo/vnl_netlib.h> // dnlaso_()
00015 
00016 static vnl_sparse_symmetric_eigensystem * current_system = 0;
00017 
00018 #ifdef VCL_SUNPRO_CC
00019 # define FUNCTION extern "C"
00020 #else
00021 # define FUNCTION static
00022 #endif
00023 
00024 //------------------------------------------------------------
00025 //: Callback for multiplying our matrix by a number of vectors.
00026 //  The input is p, which is an NxM matrix.
00027 //  This function returns q = A p, where A is the current sparse matrix.
00028 FUNCTION
00029 void sse_op_callback(const long* n,
00030                      const long* m,
00031                      const double* p,
00032                      double* q)
00033 {
00034   assert(current_system != 0);
00035 
00036   current_system->CalculateProduct(*n,*m,p,q);
00037 }
00038 
00039 //------------------------------------------------------------
00040 //: Callback for saving the Lanczos vectors as required by dnlaso.
00041 // If k=0, save the m columns of q as the (j-m+1)th through jth
00042 // vectors.  If k=1 then return the (j-m+1)th through jth vectors in
00043 // q.
00044 FUNCTION
00045 void sse_iovect_callback(const long* n,
00046                          const long* m,
00047                          double* q,
00048                          const long* j,
00049                          const long* k)
00050 {
00051   assert(current_system != 0);
00052 
00053   if (*k==0)
00054     current_system->SaveVectors(*n,*m,q,*j-*m);
00055   else if (*k==1)
00056     current_system->RestoreVectors(*n,*m,q,*j-*m);
00057 }
00058 
00059 vnl_sparse_symmetric_eigensystem::vnl_sparse_symmetric_eigensystem()
00060   : nvalues(0), vectors(0), values(0)
00061 {
00062 }
00063 
00064 vnl_sparse_symmetric_eigensystem::~vnl_sparse_symmetric_eigensystem()
00065 {
00066   delete[] vectors; vectors = 0;
00067   delete[] values; values = 0;
00068   for (unsigned i=0; i<temp_store.size(); ++i)
00069     delete temp_store[i];
00070   temp_store.clear();
00071 }
00072 
00073 //------------------------------------------------------------
00074 //: Here is where the fortran converted code gets called.
00075 // The sparse matrix M is assumed to be symmetric.  The n smallest
00076 // eigenvalues and their corresponding eigenvectors are calculated if
00077 // smallest is true (the default).  Otherwise the n largest eigenpairs
00078 // are found.  The accuracy of the eigenvalues is to nfigures decimal
00079 // digits.  Returns 0 if successful, non-zero otherwise.
00080 int vnl_sparse_symmetric_eigensystem::CalculateNPairs(vnl_sparse_matrix<double>& M,
00081                                                       int n,
00082                                                       bool smallest,
00083                                                       long nfigures)
00084 {
00085   mat = &M;
00086 
00087   // Clear current vectors.
00088   if (vectors) {
00089     delete[] vectors; vectors = 0;
00090     delete[] values; values = 0;
00091   }
00092   nvalues = 0;
00093 
00094   current_system = this;
00095 
00096   long dim = mat->columns();
00097   long nvals = (smallest)?-n:n;
00098   long nperm = 0;
00099   long nmval = n;
00100   long nmvec = dim;
00101   vcl_vector<double> temp_vals(n*4);
00102   vcl_vector<double> temp_vecs(n*dim);
00103 
00104   // set nblock = vcl_max(10, dim/6) :
00105   long nblock = (dim<60) ? dim/6 : 10;
00106 
00107   // isn't this rather a lot ? -- fsm
00108   long maxop = dim*10;      // dim*20;
00109 
00110   // set maxj = vcl_max(40, maxop*nblock, 6*nblock+1) :
00111   long maxj = maxop*nblock; // 2*n+1;
00112   long t1 = 6*nblock+1;
00113   if (maxj < t1) maxj = t1;
00114   if (maxj < 40) maxj = 40;
00115 
00116   // Calculate size of workspace needed.  These expressions come from
00117   // the LASO documentation.
00118   int work_size = dim*nblock;
00119   int t2 = maxj*(2*nblock+3) + 2*n + 6 + (2*nblock+2)*(nblock+1);
00120   if (work_size < t2) work_size = t2;
00121   work_size += 2*dim*nblock + maxj*(nblock + n + 2) + 2*nblock*nblock + 3*n;
00122   vcl_vector<double> work(work_size+10);
00123 
00124   // Set starting vectors to zero.
00125   for (int i=0; i<dim*nblock; ++i)
00126     work[i] = 0.0;
00127 
00128   vcl_vector<long> ind(n);
00129 
00130   long ierr = 0;
00131 
00132   v3p_netlib_dnlaso_(sse_op_callback, sse_iovect_callback,
00133                      &dim, &nvals, &nfigures, &nperm,
00134                      &nmval, &temp_vals[0],
00135                      &nmvec, &temp_vecs[0],
00136                      &nblock,
00137                      &maxop,
00138                      &maxj,
00139                      &work[0],
00140                      &ind[0],
00141                      &ierr);
00142   if (ierr > 0)
00143   {
00144     if (ierr & 0x1)
00145       vcl_cerr << "Error: vnl_sparse_symmetric_eigensystem: N < 6*NBLOCK\n";
00146     if (ierr & 0x2)
00147       vcl_cerr << "Error: vnl_sparse_symmetric_eigensystem: NFIG < 0\n";
00148     if (ierr & 0x4)
00149       vcl_cerr << "Error: vnl_sparse_symmetric_eigensystem: NMVEC < N\n";
00150     if (ierr & 0x8)
00151       vcl_cerr << "Error: vnl_sparse_symmetric_eigensystem: NPERM < 0\n";
00152     if (ierr & 0x10)
00153       vcl_cerr << "Error: vnl_sparse_symmetric_eigensystem: MAXJ < 6*NBLOCK\n";
00154     if (ierr & 0x20)
00155       vcl_cerr << "Error: vnl_sparse_symmetric_eigensystem: NVAL < max(1,NPERM)\n";
00156     if (ierr & 0x40)
00157       vcl_cerr << "Error: vnl_sparse_symmetric_eigensystem: NVAL > NMVAL\n";
00158     if (ierr & 0x80)
00159       vcl_cerr << "Error: vnl_sparse_symmetric_eigensystem: NVAL > MAXOP\n";
00160     if (ierr & 0x100)
00161       vcl_cerr << "Error: vnl_sparse_symmetric_eigensystem: NVAL > MAXJ/2\n";
00162     if (ierr & 0x200)
00163       vcl_cerr << "Error: vnl_sparse_symmetric_eigensystem: NBLOCK < 1\n";
00164   }
00165   else if (ierr < 0)
00166   {
00167     if (ierr == -1)
00168       vcl_cerr << "Error: vnl_sparse_symmetric_eigensystem:\n"
00169                << "  poor initial vectors chosen\n";
00170     else if (ierr == -2)
00171       vcl_cerr << "Error: vnl_sparse_symmetric_eigensystem:\n"
00172                << "  reached maximum operations " << maxop
00173                << " without finding all eigenvalues,\n"
00174                << "  found " << nperm << " eigenvalues\n";
00175     else if (ierr == -8)
00176       vcl_cerr << "Error: vnl_sparse_symmetric_eigensystem:\n"
00177                << "  disastrous loss of orthogonality - internal error\n";
00178   }
00179 
00180   // Copy the eigenvalues and vectors.
00181   nvalues = n;
00182   vectors = new vnl_vector<double>[n];
00183   values = new double[n];
00184   for (int i=0; i<n; ++i) {
00185     values[i] = temp_vals[i];
00186 #if 0
00187     vcl_cout << "value " << temp_vals[i]
00188              << " accuracy " << temp_vals[i+n*2] << vcl_endl;
00189 #endif
00190     vnl_vector<double> vec(dim,0.0);
00191     for (int j=0; j<dim; ++j)
00192       vec[j] = temp_vecs[j + dim*i];
00193     vectors[i] = vec;
00194   }
00195 
00196   // Delete temporary space.
00197   for (unsigned i=0; i<temp_store.size(); ++i)
00198     delete [] temp_store[i];
00199   temp_store.clear();
00200 
00201   return ierr;
00202 }
00203 
00204 //------------------------------------------------------------
00205 //: Callback from solver to calculate the product A p.
00206 int vnl_sparse_symmetric_eigensystem::CalculateProduct(int n, int m,
00207                                                        const double* p,
00208                                                        double* q)
00209 {
00210   // Call the special multiply method on the matrix.
00211   mat->mult(n,m,p,q);
00212 
00213   return 0;
00214 }
00215 
00216 //------------------------------------------------------------
00217 //: Callback to store vectors for dnlaso.
00218 int vnl_sparse_symmetric_eigensystem::SaveVectors(int n, int m,
00219                                                   const double* q,
00220                                                   int base)
00221 {
00222   // Store the contents of q.  Basically this is a fifo.  When a write
00223   // with base=0 is called, we start another fifo.
00224   if (base == 0) {
00225     for (unsigned i=0; i<temp_store.size(); ++i)
00226       delete temp_store[i];
00227     temp_store.clear();
00228   }
00229 
00230   double* temp = new double[n*m];
00231   vcl_memcpy(temp,q,n*m*sizeof(double));
00232 #ifdef DEBUG
00233     vcl_cout << "Save vectors " << base << ' ' << temp << '\n';
00234 #endif
00235 
00236   temp_store.push_back(temp);
00237 
00238   return 0;
00239 }
00240 
00241 //------------------------------------------------------------
00242 //: Callback to restore vectors for dnlaso.
00243 int vnl_sparse_symmetric_eigensystem::RestoreVectors(int n, int m,
00244                                                      double* q,
00245                                                      int base)
00246 {
00247   // Store the contents of q.  Basically this is a fifo.  When a read
00248   // with base=0 is called, we start another fifo.
00249   static int read_idx = 0;
00250   if (base == 0)
00251     read_idx = 0;
00252 
00253   double* temp = temp_store[read_idx];
00254   vcl_memcpy(q,temp,n*m*sizeof(double));
00255 #ifdef DEBUG
00256     vcl_cout << "Restore vectors " << base << ' ' << temp << '\n';
00257 #endif
00258 
00259   read_idx++;
00260   return 0;
00261 }
00262 
00263 //------------------------------------------------------------
00264 //: Return a calculated eigenvector.
00265 vnl_vector<double> vnl_sparse_symmetric_eigensystem::get_eigenvector(int i) const
00266 {
00267   assert(i>=0 && i<nvalues);
00268   return vectors[i];
00269 }
00270 
00271 double vnl_sparse_symmetric_eigensystem::get_eigenvalue(int i) const
00272 {
00273   assert(i>=0 && i<nvalues);
00274   return values[i];
00275 }

Generated on Sat Nov 22 05:06:20 2008 for core/vnl by  doxygen 1.5.1