arpack.cpp

Go to the documentation of this file.
00001 /*
00002  * This program is free software; you can redistribute it and/or modify
00003  * it under the terms of the GNU General Public License as published by
00004  * the Free Software Foundation; either version 3 of the License, or
00005  * (at your option) any later version.
00006  *
00007  * Written (W) 2011 Sergey Lisitsyn
00008  * Copyright (C) 2011 Berlin Institute of Technology and Max-Planck-Society
00009  */
00010 
00011 #include <shogun/mathematics/arpack.h>
00012 #ifdef HAVE_ARPACK
00013 #ifdef HAVE_LAPACK
00014 #include <shogun/lib/config.h>
00015 #include <cblas.h>
00016 #include <shogun/mathematics/lapack.h>
00017 #include <shogun/lib/common.h>
00018 #include <shogun/io/SGIO.h>
00019 #include <string.h>
00020 
00021 using namespace shogun;
00022 
00023 namespace shogun
00024 {
00025 
00026 void arpack_dsaeupd_wrap(double* matrix, double* rhs_diag, int n, int nev, const char* which, 
00027                          int mode, bool pos, double shift, double tolerance, double* eigenvalues, 
00028                          double* eigenvectors, int& status)
00029 {
00030     // loop vars
00031     int i,j;
00032 
00033     // check if nev is greater than n
00034     if (nev>n)
00035         SG_SERROR("Number of required eigenpairs is greater than order of the matrix");
00036 
00037     // check specified mode
00038     if (mode!=1 && mode!=3)
00039         SG_SERROR("Mode not supported yet");
00040 
00041     // init ARPACK's reverse communication parameter 
00042     // (should be zero initially)
00043     int ido = 0;
00044 
00045     // specify general or non-general eigenproblem will be solved
00046     // w.r.t. to given rhs_diag
00047     char bmat[2] = "I";
00048     if (rhs_diag)
00049         bmat[0] = 'G';
00050 
00051     // init tolerance (zero means machine precision)
00052     double tol = tolerance;
00053 
00054     // allocate array to hold residuals
00055     double* resid = SG_MALLOC(double, n);
00056     // fill residual vector with ones
00057     for (i=0; i<n; i++)
00058         resid[i] = 1.0;
00059 
00060     // set number of Lanczos basis vectors to be used
00061     // (with max(4*nev,n) sufficient for most tasks)
00062     int ncv = nev*4>n ? n : nev*4;
00063 
00064     // allocate array 'v' for dsaupd routine usage
00065     int ldv = n;
00066     double* v = SG_MALLOC(double, ldv*ncv);
00067 
00068     // init array for i/o params for routine
00069     int* iparam = SG_MALLOC(int, 11);
00070     // specify method for selecting implicit shifts (1 - exact shifts) 
00071     iparam[0] = 1;
00072     // specify max number of iterations
00073     iparam[2] = 3*n;
00074     // set the computation mode (1 for regular or 3 for shift-inverse)
00075     iparam[6] = mode;
00076 
00077     // init array indicating locations of vectors for routine callback
00078     int* ipntr = SG_CALLOC(int, 11);
00079 
00080     // allocate workaround arrays
00081     double* workd = SG_MALLOC(double, 3*n);
00082     int lworkl = ncv*(ncv+8);
00083     double* workl = SG_MALLOC(double, lworkl);
00084 
00085     // init info holding status (1 means that residual vector is provided initially)
00086     int info = 1;
00087 
00088     // which eigenpairs to find
00089     char* which_ = strdup(which);
00090     // All
00091     char* all_ = strdup("A");
00092 
00093     // ipiv for LUP factorization
00094     int* ipiv = NULL;
00095     // shift-invert mode init
00096     if (mode==3)
00097     {
00098         // subtract shift from main diagonal if necessary
00099         if (shift!=0.0)
00100         {
00101             SG_SDEBUG("ARPACK: Subtracting shift\n");
00102             // if right hand side diagonal matrix is provided
00103             if (rhs_diag)
00104                 // subtract I*diag(rhs_diag)
00105                 for (i=0; i<n; i++)
00106                     matrix[i*n+i] -= shift*rhs_diag[i];
00107             else
00108                 // subtract I
00109                 for (i=0; i<n; i++)
00110                     matrix[i*n+i] -= shift;
00111         }
00112         
00113         // compute factorization according to pos value
00114         if (pos)
00115         {
00116             // with Cholesky
00117             SG_SDEBUG("ARPACK: Using Cholesky factorization.\n");
00118             clapack_dpotrf(CblasColMajor,CblasUpper,n,matrix,n);
00119         }
00120         else
00121         {
00122             // with LUP
00123             SG_SDEBUG("ARPACK: Using LUP factorization.\n");
00124             ipiv = SG_CALLOC(int, n);
00125             clapack_dgetrf(CblasColMajor,n,n,matrix,n,ipiv);
00126         }
00127     }
00128     // main computation loop
00129     SG_SDEBUG("ARPACK: Starting main computation DSAUPD loop.\n");
00130     do   
00131     {
00132         dsaupd_(&ido, bmat, &n, which_, &nev, &tol, resid,
00133                 &ncv, v, &ldv, iparam, ipntr, workd, workl,
00134                 &lworkl, &info);
00135 
00136         if ((ido==1)||(ido==-1)||(ido==2))
00137         {
00138             if (mode==1)
00139             {
00140                 // compute (workd+ipntr[1]-1) = A*(workd+ipntr[0]-1)
00141                 cblas_dsymv(CblasColMajor,CblasUpper,
00142                             n,1.0,matrix,n,
00143                             (workd+ipntr[0]-1),1,
00144                             0.0,(workd+ipntr[1]-1),1);
00145             }
00146             if (mode==3)
00147             {
00148                 if (!rhs_diag)
00149                 {
00150                     for (i=0; i<n; i++)
00151                         (workd+ipntr[1]-1)[i] = (workd+ipntr[0]-1)[i];
00152 
00153                     if (pos)
00154                         clapack_dpotrs(CblasColMajor,CblasUpper,n,1,matrix,n,(workd+ipntr[1]-1),n);
00155                     else 
00156                         clapack_dgetrs(CblasColMajor,CblasNoTrans,n,1,matrix,n,ipiv,(workd+ipntr[1]-1),n);
00157                 }
00158                 else
00159                 {
00160                     if (ido==-1)
00161                     {
00162                         for (i=0; i<n; i++)
00163                             (workd+ipntr[1]-1)[i] = rhs_diag[i]*(workd+ipntr[0]-1)[i];
00164                         
00165                         if (pos)
00166                             clapack_dpotrs(CblasColMajor,CblasUpper,n,1,matrix,n,(workd+ipntr[1]-1),n);
00167                         else 
00168                             clapack_dgetrs(CblasColMajor,CblasNoTrans,n,1,matrix,n,ipiv,(workd+ipntr[1]-1),n);
00169                     }
00170                     if (ido==1)
00171                     {
00172                         for (i=0; i<n; i++)
00173                             (workd+ipntr[1]-1)[i] = (workd+ipntr[2]-1)[i];
00174 
00175                         if (pos)
00176                             clapack_dpotrs(CblasColMajor,CblasUpper,n,1,matrix,n,(workd+ipntr[1]-1),n);
00177                         else 
00178                             clapack_dgetrs(CblasColMajor,CblasNoTrans,n,1,matrix,n,ipiv,(workd+ipntr[1]-1),n);
00179                     }
00180                     if (ido==2)
00181                     {
00182                         for (i=0; i<n; i++)
00183                             (workd+ipntr[1]-1)[i] = rhs_diag[i]*(workd+ipntr[0]-1)[i]; 
00184                     }
00185                 }
00186             }
00187         }
00188     } while ((ido==1)||(ido==-1)||(ido==2));
00189     
00190     if (!pos && mode==3) SG_FREE(ipiv);
00191     
00192     // check if DSAUPD failed
00193     if (info<0) 
00194     {
00195         if ((info<=-1)&&(info>=-6))
00196             SG_SWARNING("ARPACK: DSAUPD failed. Wrong parameter passed.\n");
00197         else if (info==-7)
00198             SG_SWARNING("ARPACK: DSAUPD failed. Workaround array size is not sufficient.\n");
00199         else 
00200             SG_SWARNING("ARPACK: DSAUPD failed. Error code: %d.\n", info);
00201 
00202         status = -1;
00203     }
00204     else 
00205     {
00206         if (info==1)
00207             SG_SWARNING("ARPACK: Maximum number of iterations reached.\n");
00208             
00209         // allocate select for dseupd
00210         int* select = SG_MALLOC(int, ncv);
00211         // allocate d to hold eigenvalues
00212         double* d = SG_MALLOC(double, 2*ncv);
00213         // sigma for dseupd
00214         double sigma = shift;
00215         
00216         // init ierr indicating dseupd possible errors
00217         int ierr = 0;
00218 
00219         // specify that eigenvectors are going to be computed too       
00220         int rvec = 1;
00221 
00222         SG_SDEBUG("APRACK: Starting DSEUPD.\n");
00223 
00224         // call dseupd_ routine
00225         dseupd_(&rvec, all_, select, d, v, &ldv, &sigma, bmat,
00226                 &n, which_, &nev, &tol, resid, &ncv, v, &ldv,
00227                 iparam, ipntr, workd, workl, &lworkl, &ierr);
00228 
00229         // check for errors
00230         if (ierr!=0)
00231         {
00232             SG_SWARNING("ARPACK: DSEUPD failed with status %d.\n", ierr);
00233             status = -1;
00234         }
00235         else
00236         {
00237             SG_SDEBUG("ARPACK: Storing eigenpairs.\n");
00238 
00239             // store eigenpairs to specified arrays
00240             for (i=0; i<nev; i++)
00241             {   
00242                 eigenvalues[i] = d[i];
00243             
00244                 for (j=0; j<n; j++)
00245                     eigenvectors[j*nev+i] = v[i*n+j];
00246             }
00247         }
00248         
00249         // cleanup
00250         SG_FREE(select);
00251         SG_FREE(d);
00252     }
00253 
00254     // cleanup
00255     SG_FREE(all_);
00256     SG_FREE(which_);
00257     SG_FREE(resid);
00258     SG_FREE(v);
00259     SG_FREE(iparam);
00260     SG_FREE(ipntr);
00261     SG_FREE(workd);
00262     SG_FREE(workl);
00263 };
00264 
00265 }
00266 #endif /* HAVE_LAPACK */
00267 #endif /* HAVE_ARPACK */
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

SHOGUN Machine Learning Toolbox - Documentation