double MC_Condition_Number(double **X, int dim, int expl) { int i = 0, j = 0, row = 0, column = 0; double xn = 0; DenseVector *x = new DenseVector [dim]; for (i = 0; i < expl; i++) x[i].absorb(X[i], dim, false); for (i = 0; i < expl; i++) { xn = x[i].norm(); for (j = 0; j < dim; j++) { x[i].setAt(j, x[i].getValue(j) / sqrt(xn)); } } // use CLAPACK to compute the largest and the smallest eigenvalues // use dspev_ char jobz = 'N', uplo = 'U'; long int n = expl; long int ldz = expl, lwork = 3 * expl, info = 0; double *a = new double [expl * (expl + 1) / 2]; double *s = new double [expl]; double *z = NULL; double *work = new double [lwork]; for (row = 0; row < expl; row++) { for (column = row + 1; column < expl; column++) a[row + column * (column + 1) / 2] = x[row].product(x[column]); a[row + row * (row + 1) / 2] = x[row].norm(); } // use __WXMAC__ to call vecLib //#ifdef WORDS_BIGENDIAN #ifdef __WXMAC__MMM dspev_(&jobz, &uplo, &n, a, s, z, &ldz, work, &info); #else dspev_(&jobz, &uplo, (integer*)&n, (doublereal*)a, (doublereal*)s, (doublereal*)z, (integer*)&ldz, (doublereal*)work, (integer*)&info); #endif if (!info) { double max = s[expl - 1], min = s[0]; return sqrt(max / min); } else { // cerr << "error in computing eigenvalues" << endl; wxMessageBox("error in computing eigenvalues"); return -999; } }
int local_dspev(const int* n, double* A, double* W, double* Z, const int *ldz, double* work){ //extern void dspev_(const char* jobz, const char* uplo, // const int* n, double * A, double* W, double* Z, const int* ldz, double* work, long* info); int info; dspev_(&V, &Upper, n, A, W, Z, ldz, work, &info); return info; }
void dspev(char jobz, char uplo, int n, double *dap, double *w, double *dz, int ldz, int *info) { double *work ; allot ( double *, work, 3*n ) ; dspev_ ( &jobz, &uplo, &n, dap, w, dz, &ldz, work, info ); free(work) ; }
/// Solve symmetric eigenvalue problem using CLAPACK routines. void quantfin::interfaceCLAPACK::SymmetricEigenvalueProblem( const Array<double,2>& A, ///< Symmetric Array to be decomposed. Array<double,1>& eigval, ///< Array (vector) containing all non-zero eigenvalues. Array<double,2>& eigvec, ///< Array of eigenvectors (Array, each column is an eigenvector) double eps ///< Threshold for comparison to zero, default 1e-12 ) { int i,j; long int n = A.rows(); if (n!=A.columns()) throw(std::logic_error("Array must be square")); double* ap = new double[(n*(n+1))/2]; double* pos = ap; for (i=0;i<n;i++) { for (j=0;j<=i;j++) *pos++ = A(j,i); } double* w = new double[n]; double* z = new double[n*n]; double* work = new double[3*n]; long int ldz = n; long int info = 0; char jobz = 'V'; char uplo = 'U'; dspev_(&jobz,&uplo,&n,ap,w,z,&ldz,work,&info); if (!info) { int k = n; for (i=0;i<n;i++) { if (my_abs(w[i])<=eps) k--; } Array<double,1> val(k); Array<double,2> vec(n,k); int l = 0; pos = z; for (i=0;i<n;i++) { if (my_abs(w[i])>eps) { val(l) = w[i]; for (j=0;j<n;j++) vec(j,l) = *pos++; l++; } else pos += n; } eigval.resize(k); eigvec.resize(n,k); eigval = val; eigvec = vec; } delete[] ap; delete[] w; delete[] z; delete[] work; if (info) throw(std::logic_error("Eigenvalue decomposition failed")); }
void Eigensystem( char* jobz, char* uplo, int* n, double* ap, double* w, int* ldz) { if( *jobz =='V' ) { printf( "Sorry sucka! I'm too lazy to do this.\n" ); exit(1); } /* Query and allocate the optimal workspace */ int info=0; double* work = (double*)malloc( 3 * (*n) * sizeof(double) ); /* Solve eigenproblem */ double* z; // Dummy dspev_( jobz, uplo, n, ap, w, z, ldz, work, &info ); /* Check for convergence */ if( info != 0 ) { printf( "The algorithm failed to compute eigenvalues.\n" ); exit( 1 ); } /* Free workspace */ free( (void*)work ); }
/* Subroutine */ int dspgv_(integer *itype, char *jobz, char *uplo, integer * n, doublereal *ap, doublereal *bp, doublereal *w, doublereal *z__, integer *ldz, doublereal *work, integer *info) { /* -- LAPACK driver routine (version 3.0) -- Univ. of Tennessee, Univ. of California Berkeley, NAG Ltd., Courant Institute, Argonne National Lab, and Rice University September 30, 1994 Purpose ======= DSPGV computes all the eigenvalues and, optionally, the eigenvectors of a real generalized symmetric-definite eigenproblem, of the form A*x=(lambda)*B*x, A*Bx=(lambda)*x, or B*A*x=(lambda)*x. Here A and B are assumed to be symmetric, stored in packed format, and B is also positive definite. Arguments ========= ITYPE (input) INTEGER Specifies the problem type to be solved: = 1: A*x = (lambda)*B*x = 2: A*B*x = (lambda)*x = 3: B*A*x = (lambda)*x JOBZ (input) CHARACTER*1 = 'N': Compute eigenvalues only; = 'V': Compute eigenvalues and eigenvectors. UPLO (input) CHARACTER*1 = 'U': Upper triangles of A and B are stored; = 'L': Lower triangles of A and B are stored. N (input) INTEGER The order of the matrices A and B. N >= 0. AP (input/output) DOUBLE PRECISION array, dimension (N*(N+1)/2) On entry, the upper or lower triangle of the symmetric matrix A, packed columnwise in a linear array. The j-th column of A is stored in the array AP as follows: if UPLO = 'U', AP(i + (j-1)*j/2) = A(i,j) for 1<=i<=j; if UPLO = 'L', AP(i + (j-1)*(2*n-j)/2) = A(i,j) for j<=i<=n. On exit, the contents of AP are destroyed. BP (input/output) DOUBLE PRECISION array, dimension (N*(N+1)/2) On entry, the upper or lower triangle of the symmetric matrix B, packed columnwise in a linear array. The j-th column of B is stored in the array BP as follows: if UPLO = 'U', BP(i + (j-1)*j/2) = B(i,j) for 1<=i<=j; if UPLO = 'L', BP(i + (j-1)*(2*n-j)/2) = B(i,j) for j<=i<=n. On exit, the triangular factor U or L from the Cholesky factorization B = U**T*U or B = L*L**T, in the same storage format as B. W (output) DOUBLE PRECISION array, dimension (N) If INFO = 0, the eigenvalues in ascending order. Z (output) DOUBLE PRECISION array, dimension (LDZ, N) If JOBZ = 'V', then if INFO = 0, Z contains the matrix Z of eigenvectors. The eigenvectors are normalized as follows: if ITYPE = 1 or 2, Z**T*B*Z = I; if ITYPE = 3, Z**T*inv(B)*Z = I. If JOBZ = 'N', then Z is not referenced. LDZ (input) INTEGER The leading dimension of the array Z. LDZ >= 1, and if JOBZ = 'V', LDZ >= max(1,N). WORK (workspace) DOUBLE PRECISION array, dimension (3*N) INFO (output) INTEGER = 0: successful exit < 0: if INFO = -i, the i-th argument had an illegal value > 0: DPPTRF or DSPEV returned an error code: <= N: if INFO = i, DSPEV failed to converge; i off-diagonal elements of an intermediate tridiagonal form did not converge to zero. > N: if INFO = n + i, for 1 <= i <= n, then the leading minor of order i of B is not positive definite. The factorization of B could not be completed and no eigenvalues or eigenvectors were computed. ===================================================================== Test the input parameters. Parameter adjustments */ /* Table of constant values */ static integer c__1 = 1; /* System generated locals */ integer z_dim1, z_offset, i__1; /* Local variables */ static integer neig, j; extern logical lsame_(char *, char *); extern /* Subroutine */ int dspev_(char *, char *, integer *, doublereal * , doublereal *, doublereal *, integer *, doublereal *, integer *); static char trans[1]; static logical upper; extern /* Subroutine */ int dtpmv_(char *, char *, char *, integer *, doublereal *, doublereal *, integer *), dtpsv_(char *, char *, char *, integer *, doublereal *, doublereal *, integer *); static logical wantz; extern /* Subroutine */ int xerbla_(char *, integer *), dpptrf_( char *, integer *, doublereal *, integer *), dspgst_( integer *, char *, integer *, doublereal *, doublereal *, integer *); #define z___ref(a_1,a_2) z__[(a_2)*z_dim1 + a_1] --ap; --bp; --w; z_dim1 = *ldz; z_offset = 1 + z_dim1 * 1; z__ -= z_offset; --work; /* Function Body */ wantz = lsame_(jobz, "V"); upper = lsame_(uplo, "U"); *info = 0; if (*itype < 0 || *itype > 3) { *info = -1; } else if (! (wantz || lsame_(jobz, "N"))) { *info = -2; } else if (! (upper || lsame_(uplo, "L"))) { *info = -3; } else if (*n < 0) { *info = -4; } else if (*ldz < 1 || wantz && *ldz < *n) { *info = -9; } if (*info != 0) { i__1 = -(*info); xerbla_("DSPGV ", &i__1); return 0; } /* Quick return if possible */ if (*n == 0) { return 0; } /* Form a Cholesky factorization of B. */ dpptrf_(uplo, n, &bp[1], info); if (*info != 0) { *info = *n + *info; return 0; } /* Transform problem to standard eigenvalue problem and solve. */ dspgst_(itype, uplo, n, &ap[1], &bp[1], info); dspev_(jobz, uplo, n, &ap[1], &w[1], &z__[z_offset], ldz, &work[1], info); if (wantz) { /* Backtransform eigenvectors to the original problem. */ neig = *n; if (*info > 0) { neig = *info - 1; } if (*itype == 1 || *itype == 2) { /* For A*x=(lambda)*B*x and A*B*x=(lambda)*x; backtransform eigenvectors: x = inv(L)'*y or inv(U)*y */ if (upper) { *(unsigned char *)trans = 'N'; } else { *(unsigned char *)trans = 'T'; } i__1 = neig; for (j = 1; j <= i__1; ++j) { dtpsv_(uplo, trans, "Non-unit", n, &bp[1], &z___ref(1, j), & c__1); /* L10: */ } } else if (*itype == 3) { /* For B*A*x=(lambda)*x; backtransform eigenvectors: x = L*y or U'*y */ if (upper) { *(unsigned char *)trans = 'T'; } else { *(unsigned char *)trans = 'N'; } i__1 = neig; for (j = 1; j <= i__1; ++j) { dtpmv_(uplo, trans, "Non-unit", n, &bp[1], &z___ref(1, j), & c__1); /* L20: */ } } } return 0; /* End of DSPGV */ } /* dspgv_ */
/** Get eigenvectors and eigenvalues. They will be stored in descending * order (largest eigenvalue first). */ int DataSet_Modes::CalcEigen(DataSet_2D const& mIn, int n_to_calc) { #ifdef NO_MATHLIB mprinterr("Error: modes: Compiled without ARPACK/LAPACK/BLAS routines.\n"); return 1; #else bool eigenvaluesOnly = false; int info = 0; if (mIn.MatrixKind() != DataSet_2D::HALF) { mprinterr("Error: DataSet_Modes: Eigenvector/value calc only for symmetric matrices.\n"); return 1; } // If number to calc is 0, assume we want eigenvalues only if (n_to_calc < 1) { if (n_to_calc == 0) eigenvaluesOnly = true; nmodes_ = (int)mIn.Ncols(); } else nmodes_ = n_to_calc; if (nmodes_ > (int)mIn.Ncols()) { mprintf("Warning: Specified # of eigenvalues to calc (%i) > matrix dimension (%i).\n", nmodes_, mIn.Ncols()); nmodes_ = mIn.Ncols(); mprintf("Warning: Only calculating %i eigenvalues.\n", nmodes_); } if (eigenvaluesOnly) mprintf("\tCalculating %i eigenvalues only.\n", nmodes_); else mprintf("\tCalculating %i eigenvectors and eigenvalues.\n", nmodes_); // ----------------------------------------------------------------- if (nmodes_ == (int)mIn.Ncols()) { // Calculate all eigenvalues (and optionally eigenvectors). char jobz = 'V'; // Default: Calc both eigenvectors and eigenvalues vecsize_ = mIn.Ncols(); // Check if only calculating eigenvalues if (eigenvaluesOnly) { jobz = 'N'; vecsize_ = 1; } // Set up space to hold eigenvectors if (evectors_ != 0) delete[] evectors_; if (!eigenvaluesOnly) evectors_ = new double[ nmodes_ * vecsize_ ]; else evectors_ = 0; // Set up space to hold eigenvalues if (evalues_ != 0) delete[] evalues_; evalues_ = new double[ nmodes_ ]; // Create copy of matrix since call to dspev destroys it double* mat = mIn.MatrixArray(); // Lower triangle; not upper since fortran array layout is inverted w.r.t. C/C++ char uplo = 'L'; // Allocate temporary workspace double* work = new double[ 3 * nmodes_ ]; // NOTE: The call to dspev is supposed to store eigenvectors in columns. // However as mentioned above fortran array layout is inverted // w.r.t. C/C++ so eigenvectors end up in rows. // NOTE: Eigenvalues/vectors are returned in ascending order. dspev_(jobz, uplo, nmodes_, mat, evalues_, evectors_, vecsize_, work, info); // If no eigenvectors calcd set vecsize to 0 if (evectors_==0) vecsize_ = 0; delete[] work; delete[] mat; if (info != 0) { if (info < 0) { mprinterr("Internal Error: from dspev: Argument %i had illegal value.\n", -info); mprinterr("Args: %c %c %i matrix %x %x %i work %i\n", jobz, uplo, nmodes_, evalues_, evectors_, vecsize_, info); } else { // info > 0 mprinterr("Internal Error: from dspev: The algorithm failed to converge.\n"); mprinterr("%i off-diagonal elements of an intermediate tridiagonal form\n", info); mprinterr("did not converge to zero.\n"); } return 1; } // ----------------------------------------------------------------- } else { // Calculate up to n-1 eigenvalues/vectors using the Implicitly Restarted // Arnoldi iteration. // FIXME: Eigenvectors obtained with this method appear to have signs // flipped compared to full method - is dot product wrong? int nelem = mIn.Ncols(); // Dimension of input matrix (N) // Allocate memory to store eigenvectors vecsize_ = mIn.Ncols(); int ncv; // # of columns of the matrix V (evectors_), <= N (mIn.Ncols()) if (evectors_!=0) delete[] evectors_; if (nmodes_*2 <= nelem) ncv = nmodes_*2; else ncv = nelem; evectors_ = new double[ ncv * nelem ]; // Temporary storage for eigenvectors to avoid memory overlap in dseupd double* eigenvectors = new double[ ncv * nelem ]; // Allocate memory to store eigenvalues if ( evalues_ != 0) delete[] evalues_; evalues_ = new double[ nelem ] ; // NOTE: Should this be nmodes? // Allocate workspace double* workd = new double[ 3 * nelem ]; int lworkl = ncv * (ncv+8); // NOTE: should this be ncv^2 * (ncv+8) double* workl = new double[ lworkl ]; double* resid = new double[ nelem ]; // Set parameters for dsaupd (Arnolid) int ido = 0; // Reverse comm. flag; 0 = first call // The iparam array is used to set parameters for the calc. int iparam[11]; std::fill( iparam, iparam + 11, 0 ); iparam[0] = 1; // Method for selecting implicit shifts; 1 = exact iparam[2] = 300; // Max # of iterations allowed iparam[3] = 1; // blocksize to be used in the recurrence (code works with only 1). iparam[6] = 1; // Type of eigenproblem being solved; 1: A*x = lambda*x double tol = 0; // Stopping criterion (tolerance); 0 = arpack default char bmat = 'I'; // Type of matrix B that defines semi-inner product; I = identity char which[2]; // Which of the Ritz values of OP to compute; which[0] = 'L'; // 'LA' = compute the NEV largest eigenvalues which[1] = 'A'; // The ipntr array will hold starting locations in workd and workl arrays // for matrices/vectors used by the Lanczos iteration. int ipntr[11]; std::fill( ipntr, ipntr + 11, 0 ); // Create copy of matrix since it will be modified double* mat = mIn.MatrixArray(); // LOOP bool loop = false; do { if (loop) { // Dot products double* target = workd + (ipntr[1] - 1); // -1 since fortran indexing starts at 1 double* vec = workd + (ipntr[0] - 1); std::fill( target, target + nelem, 0 ); for(int i = 0; i < nelem; i++) { for(int j = i; j < nelem; j++) { int ind = nelem * i + j - (i * (i + 1)) / 2; target[i] += mat[ind] * vec[j]; if(i != j) target[j] += mat[ind] * vec[i]; } } } dsaupd_(ido, bmat, nelem, which, nmodes_, tol, resid, ncv, eigenvectors, nelem, iparam, ipntr, workd, workl, lworkl, info); loop = (ido == -1 || ido == 1); } while ( loop ); // END LOOP if (info != 0) { mprinterr("Error: DataSet_Modes: dsaupd returned %i\n",info); } else { int rvec = 1; char howmny = 'A'; double sigma = 0.0; int* select = new int[ ncv ]; dseupd_(rvec, howmny, select, evalues_, evectors_, nelem, sigma, bmat, nelem, which, nmodes_, tol, resid, ncv, eigenvectors, nelem, iparam, ipntr, workd, workl, lworkl, info); delete[] select; } delete[] mat; delete[] workl; delete[] workd; delete[] resid; delete[] eigenvectors; if (info != 0) { mprinterr("Error: DataSet_Modes: dseupd returned %i\n",info); return 1; } } // Eigenvalues and eigenvectors are in ascending order. Resort so that // they are in descending order (i.e. largest eigenvalue first). int pivot = nmodes_ / 2; int nmode = nmodes_ - 1; double* vtmp = 0; if (evectors_ != 0) vtmp = new double[ vecsize_ ]; for (int mode = 0; mode < pivot; ++mode) { // Swap eigenvalue double eval = evalues_[mode]; evalues_[mode] = evalues_[nmode]; evalues_[nmode] = eval; // Swap eigenvector if (vtmp != 0) { double* Vec0 = evectors_ + (mode * vecsize_); double* Vec1 = evectors_ + (nmode * vecsize_); std::copy( Vec0, Vec0 + vecsize_, vtmp ); std::copy( Vec1, Vec1 + vecsize_, Vec0 ); std::copy( vtmp, vtmp + vecsize_, Vec1 ); } --nmode; } if (vtmp != 0) delete[] vtmp; return 0; #endif }