00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011 #include <shogun/mathematics/arpack.h>
00012 #ifdef HAVE_ARPACK
00013 #ifdef HAVE_LAPACK
00014 #include <shogun/io/SGIO.h>
00015 #include <string.h>
00016 #include <shogun/mathematics/lapack.h>
00017
00018 #ifdef HAVE_SUPERLU
00019 #include <superlu/slu_ddefs.h>
00020 #endif
00021
00022
00024 extern "C" void dsaupd_(int *ido, char *bmat, int *n, char *which,
00025 int *nev, double *tol, double *resid, int *ncv,
00026 double *v, int *ldv, int *iparam, int *ipntr,
00027 double *workd, double *workl, int *lworkl,
00028 int *info);
00029
00031 extern "C" void dseupd_(int *rvec, char *All, int *select, double *d,
00032 double *v, int *ldv, double *sigma,
00033 char *bmat, int *n, char *which, int *nev,
00034 double *tol, double *resid, int *ncv, double *tv,
00035 int *tldv, int *iparam, int *ipntr, double *workd,
00036 double *workl, int *lworkl, int *ierr);
00037
00038 using namespace shogun;
00039
00040 namespace shogun
00041 {
00042 void arpack_dsxupd(double* matrix, double* rhs, bool is_rhs_diag, int n, int nev,
00043 const char* which, bool use_superlu, int mode, bool pos, bool cov,
00044 double shift, double tolerance, double* eigenvalues,
00045 double* eigenvectors, int& status)
00046 {
00047
00048 int i,j;
00049
00050 if (use_superlu)
00051 {
00052 #ifndef HAVE_SUPERLU
00053 use_superlu=false;
00054 SG_SINFO("Required SUPERLU isn't available in this configuration\n");
00055 #endif
00056 }
00057
00058
00059 if (nev>n)
00060 SG_SERROR("Number of required eigenpairs is greater than order of the matrix\n");
00061
00062
00063 if (mode!=1 && mode!=3)
00064 SG_SERROR("Mode not supported yet\n");
00065
00066
00067
00068 int ido = 0;
00069
00070
00071
00072 char bmat[2] = "I";
00073 if (rhs)
00074 bmat[0] = 'G';
00075
00076
00077 double tol = tolerance;
00078
00079
00080 double* resid = SG_MALLOC(double, n);
00081
00082 for (i=0; i<n; i++)
00083 resid[i] = 1.0;
00084
00085
00086
00087 int ncv = nev*4>n ? n : nev*4;
00088
00089
00090 int ldv = n;
00091 double* v = SG_MALLOC(double, ldv*ncv);
00092
00093
00094 int* iparam = SG_MALLOC(int, 11);
00095
00096 iparam[0] = 1;
00097
00098 iparam[2] = 3*n;
00099
00100 iparam[6] = mode;
00101
00102
00103 int* ipntr = SG_CALLOC(int, 11);
00104
00105
00106 double* workd = SG_MALLOC(double, 3*n);
00107 int lworkl = ncv*(ncv+8);
00108 double* workl = SG_MALLOC(double, lworkl);
00109
00110
00111 int info = 0;
00112
00113
00114 char* which_ = strdup(which);
00115
00116 char* all_ = strdup("A");
00117
00118
00119 int* ipiv = NULL;
00120
00121 #ifdef HAVE_SUPERLU
00122 char equed[1];
00123 void* work = NULL;
00124 int lwork = 0;
00125 SuperMatrix slu_A, slu_L, slu_U, slu_B, slu_X;
00126 superlu_options_t options;
00127 SuperLUStat_t stat;
00128 mem_usage_t mem_usage;
00129 int *perm_c=NULL, *perm_r=NULL, *etree=NULL;
00130 double *R=NULL, *C=NULL;
00131 if (mode==3 && use_superlu)
00132 {
00133 perm_c = intMalloc(n);
00134 perm_r = intMalloc(n);
00135 etree = intMalloc(n);
00136 R = doubleMalloc(n);
00137 C = doubleMalloc(n);
00138 }
00139 double ferr;
00140 double berr;
00141 double rcond;
00142 double rpg;
00143 int slu_info;
00144 double* slu_Bv=NULL;
00145 double* slu_Xv=NULL;
00146 #endif
00147
00148
00149 if (mode==3)
00150 {
00151
00152 if (shift!=0.0)
00153 {
00154 SG_SDEBUG("ARPACK: Subtracting shift\n");
00155
00156
00157 if (rhs && is_rhs_diag)
00158
00159 for (i=0; i<n; i++)
00160 matrix[i*n+i] -= rhs[i]*shift;
00161
00162 else
00163
00164 for (i=0; i<n; i++)
00165 matrix[i*n+i] -= shift;
00166 }
00167
00168 if (use_superlu)
00169 {
00170 #ifdef HAVE_SUPERLU
00171 SG_SDEBUG("SUPERLU: Constructing sparse matrix.\n");
00172 int nnz = 0;
00173
00174 for (i=0; i<n*n; i++)
00175 {
00176 if (matrix[i]!=0.0)
00177 nnz++;
00178 }
00179
00180 double* val = doubleMalloc(nnz);
00181 int* rowind = intMalloc(nnz);
00182 int* colptr = intMalloc(n+1);
00183 nnz = 0;
00184
00185 for (i=0; i<n; i++)
00186 {
00187 colptr[i] = nnz;
00188 for (j=0; j<n; j++)
00189 {
00190 if (matrix[i*n+j]!=0.0)
00191 {
00192 val[nnz] = matrix[i*n+j];
00193 rowind[nnz] = j;
00194 nnz++;
00195 }
00196 }
00197 }
00198 colptr[i] = nnz;
00199
00200 dCreate_CompCol_Matrix(&slu_A,n,n,nnz,val,rowind,colptr,SLU_NC,SLU_D,SLU_GE);
00201
00202
00203 set_default_options(&options);
00204
00205
00206
00207 options.SymmetricMode = YES;
00208 options.ColPerm = MMD_AT_PLUS_A;
00209 options.DiagPivotThresh = 0.001;
00210 StatInit(&stat);
00211
00212
00213 slu_info = 0;
00214 slu_Bv = doubleMalloc(n);
00215 slu_Xv = doubleMalloc(n);
00216 dCreate_Dense_Matrix(&slu_B,n,1,slu_Bv,n,SLU_DN,SLU_D,SLU_GE);
00217 dCreate_Dense_Matrix(&slu_X,n,1,slu_Xv,n,SLU_DN,SLU_D,SLU_GE);
00218 slu_B.ncol = 0;
00219 SG_SDEBUG("SUPERLU: Factorizing\n");
00220 dgssvx(&options, &slu_A, perm_c, perm_r, etree, equed, R, C,
00221 &slu_L, &slu_U, work, lwork, &slu_B, &slu_X, &rpg, &rcond, &ferr, &berr,
00222 &mem_usage,&stat,&slu_info);
00223 slu_B.ncol = 1;
00224 if (slu_info)
00225 {
00226 SG_SERROR("SUPERLU: Failed to factorize matrix, got %d code\n", slu_info);
00227 }
00228 options.Fact = FACTORED;
00229 #endif
00230 }
00231 else
00232 {
00233
00234 if (pos)
00235 {
00236
00237 SG_SDEBUG("ARPACK: Using Cholesky factorization.\n");
00238 clapack_dpotrf(CblasColMajor,CblasUpper,n,matrix,n);
00239 }
00240 else
00241 {
00242
00243 SG_SDEBUG("ARPACK: Using LUP factorization.\n");
00244 ipiv = SG_CALLOC(int, n);
00245 clapack_dgetrf(CblasColMajor,n,n,matrix,n,ipiv);
00246 }
00247 }
00248 }
00249
00250 SG_SDEBUG("ARPACK: Starting main computation DSAUPD loop.\n");
00251 do
00252 {
00253 dsaupd_(&ido, bmat, &n, which_, &nev, &tol, resid,
00254 &ncv, v, &ldv, iparam, ipntr, workd, workl,
00255 &lworkl, &info);
00256
00257 if ((ido==1)||(ido==-1)||(ido==2))
00258 {
00259 if (mode==1)
00260 {
00261 if (!cov)
00262 {
00263
00264 cblas_dsymv(CblasColMajor,CblasUpper,
00265 n,1.0,matrix,n,
00266 (workd+ipntr[0]-1),1,
00267 0.0,(workd+ipntr[1]-1),1);
00268 }
00269 else
00270 {
00271 cblas_dsymv(CblasColMajor,CblasUpper,
00272 n,1.0,matrix,n,
00273 (workd+ipntr[0]-1),1,
00274 0.0,(workd+ipntr[1]-1),1);
00275 cblas_dsymv(CblasColMajor,CblasUpper,
00276 n,1.0,matrix,n,
00277 (workd+ipntr[1]-1),1,
00278 0.0,(workd+ipntr[0]-1),1);
00279 cblas_dcopy(n,workd+ipntr[0]-1,1,workd+ipntr[1]-1,1);
00280 }
00281 }
00282 if (mode==3)
00283 {
00284 if (!rhs)
00285 {
00286 if (use_superlu)
00287 {
00288 #ifdef HAVE_SUPERLU
00289
00290 for (i=0; i<n; i++)
00291 slu_Bv[i] = (workd+ipntr[0]-1)[i];
00292 slu_info = 0;
00293
00294 dgssvx(&options, &slu_A, perm_c, perm_r, etree, equed, R, C,
00295 &slu_L, &slu_U, work, lwork, &slu_B, &slu_X, &rpg, &rcond,
00296 &ferr, &berr, &mem_usage, &stat, &slu_info);
00297 if (slu_info)
00298 SG_SERROR("SUPERLU: GOT %d\n", slu_info);
00299
00300 for (i=0; i<n; i++)
00301 (workd+ipntr[1]-1)[i] = slu_Xv[i];
00302 #endif
00303 }
00304 else
00305 {
00306 for (i=0; i<n; i++)
00307 (workd+ipntr[1]-1)[i] = (workd+ipntr[0]-1)[i];
00308 if (pos)
00309 clapack_dpotrs(CblasColMajor,CblasUpper,n,1,matrix,n,(workd+ipntr[1]-1),n);
00310 else
00311 clapack_dgetrs(CblasColMajor,CblasNoTrans,n,1,matrix,n,ipiv,(workd+ipntr[1]-1),n);
00312 }
00313 }
00314 else
00315
00316 {
00317 if (ido==-1)
00318 {
00319 if (use_superlu)
00320 {
00321 #ifdef HAVE_SUPERLU
00322 for (i=0; i<n; i++)
00323 slu_Bv[i] = (workd+ipntr[0]-1)[i];
00324 slu_info = 0;
00325 dgssvx(&options, &slu_A, perm_c, perm_r, etree, equed, R, C,
00326 &slu_L, &slu_U, work, lwork, &slu_B, &slu_X, &rpg, &rcond,
00327 &ferr, &berr, &mem_usage, &stat, &slu_info);
00328 if (slu_info)
00329 SG_SERROR("SUPERLU: GOT %d\n", slu_info);
00330 for (i=0; i<n; i++)
00331 (workd+ipntr[1]-1)[i] = slu_Xv[i];
00332 #endif
00333 }
00334 else
00335 {
00336 for (i=0; i<n; i++)
00337 (workd+ipntr[1]-1)[i] = rhs[i]*(workd+ipntr[0]-1)[i];
00338 if (pos)
00339 clapack_dpotrs(CblasColMajor,CblasUpper,n,1,matrix,n,(workd+ipntr[1]-1),n);
00340 else
00341 clapack_dgetrs(CblasColMajor,CblasNoTrans,n,1,matrix,n,ipiv,(workd+ipntr[1]-1),n);
00342 }
00343 }
00344 if (ido==1)
00345 {
00346 if (use_superlu)
00347 {
00348 #ifdef HAVE_SUPERLU
00349 for (i=0; i<n; i++)
00350 slu_Bv[i] = (workd+ipntr[2]-1)[i];
00351 slu_info = 0;
00352 dgssvx(&options, &slu_A, perm_c, perm_r, etree, equed, R, C,
00353 &slu_L, &slu_U, work, lwork, &slu_B, &slu_X, &rpg, &rcond,
00354 &ferr, &berr, &mem_usage, &stat, &slu_info);
00355 if (slu_info)
00356 SG_SERROR("SUPERLU: GOT %d\n", slu_info);
00357 for (i=0; i<n; i++)
00358 (workd+ipntr[1]-1)[i] = slu_Xv[i];
00359 #endif
00360 }
00361 else
00362 {
00363 for (i=0; i<n; i++)
00364 (workd+ipntr[1]-1)[i] = (workd+ipntr[2]-1)[i];
00365 if (pos)
00366 clapack_dpotrs(CblasColMajor,CblasUpper,n,1,matrix,n,(workd+ipntr[1]-1),n);
00367 else
00368 clapack_dgetrs(CblasColMajor,CblasNoTrans,n,1,matrix,n,ipiv,(workd+ipntr[1]-1),n);
00369 }
00370 }
00371 if (ido==2)
00372 {
00373 if (is_rhs_diag)
00374 {
00375 for (i=0; i<n; i++)
00376 (workd+ipntr[1]-1)[i] = rhs[i]*(workd+ipntr[0]-1)[i];
00377 }
00378 else
00379 {
00380 cblas_dsymv(CblasColMajor,CblasUpper,
00381 n,1.0,rhs,n,
00382 (workd+ipntr[0]-1),1,
00383 0.0,(workd+ipntr[1]-1),1);
00384 }
00385 }
00386 }
00387 }
00388 }
00389 } while ((ido==1)||(ido==-1)||(ido==2));
00390
00391 if (!pos && mode==3) SG_FREE(ipiv);
00392
00393 if (mode==3 && use_superlu)
00394 {
00395 #ifdef HAVE_SUPERLU
00396 SUPERLU_FREE(slu_Bv);
00397 SUPERLU_FREE(slu_Xv);
00398 SUPERLU_FREE(perm_r);
00399 SUPERLU_FREE(perm_c);
00400 SUPERLU_FREE(R);
00401 SUPERLU_FREE(C);
00402 SUPERLU_FREE(etree);
00403 if (lwork!=0) SUPERLU_FREE(work);
00404 Destroy_CompCol_Matrix(&slu_A);
00405 StatFree(&stat);
00406 Destroy_SuperMatrix_Store(&slu_B);
00407 Destroy_SuperMatrix_Store(&slu_X);
00408 Destroy_SuperNode_Matrix(&slu_L);
00409 Destroy_CompCol_Matrix(&slu_U);
00410 #endif
00411 }
00412
00413
00414 if (info<0)
00415 {
00416 if ((info<=-1)&&(info>=-6))
00417 SG_SWARNING("ARPACK: DSAUPD failed. Wrong parameter passed.\n");
00418 else if (info==-7)
00419 SG_SWARNING("ARPACK: DSAUPD failed. Workaround array size is not sufficient.\n");
00420 else
00421 SG_SWARNING("ARPACK: DSAUPD failed. Error code: %d.\n", info);
00422
00423 status = info;
00424 }
00425 else
00426 {
00427 if (info==1)
00428 SG_SWARNING("ARPACK: Maximum number of iterations reached.\n");
00429
00430
00431 int* select = SG_MALLOC(int, ncv);
00432
00433 double* d = SG_MALLOC(double, 2*ncv);
00434
00435 double sigma = shift;
00436
00437
00438 int ierr = 0;
00439
00440
00441 int rvec = 1;
00442
00443 SG_SDEBUG("APRACK: Starting DSEUPD.\n");
00444
00445
00446 dseupd_(&rvec, all_, select, d, v, &ldv, &sigma, bmat,
00447 &n, which_, &nev, &tol, resid, &ncv, v, &ldv,
00448 iparam, ipntr, workd, workl, &lworkl, &ierr);
00449
00450
00451 if (ierr!=0)
00452 {
00453 SG_SWARNING("ARPACK: DSEUPD failed with status %d.\n", ierr);
00454 status = -1;
00455 }
00456 else
00457 {
00458 SG_SDEBUG("ARPACK: Storing eigenpairs.\n");
00459
00460
00461 for (i=0; i<nev; i++)
00462 {
00463 eigenvalues[i] = d[i];
00464
00465 for (j=0; j<n; j++)
00466 eigenvectors[j*nev+i] = v[i*n+j];
00467 }
00468 }
00469
00470
00471 SG_FREE(select);
00472 SG_FREE(d);
00473 }
00474
00475
00476 SG_FREE(all_);
00477 SG_FREE(which_);
00478 SG_FREE(resid);
00479 SG_FREE(v);
00480 SG_FREE(iparam);
00481 SG_FREE(ipntr);
00482 SG_FREE(workd);
00483 SG_FREE(workl);
00484 };
00485 }
00486 #endif
00487 #endif