int dspgvx_(int *itype, char *jobz, char *range, char * uplo, int *n, double *ap, double *bp, double *vl, double *vu, int *il, int *iu, double *abstol, int *m, double *w, double *z__, int *ldz, double *work, int *iwork, int *ifail, int *info) { /* System generated locals */ int z_dim1, z_offset, i__1; /* Local variables */ int j; extern int lsame_(char *, char *); char trans[1]; int upper; extern int dtpmv_(char *, char *, char *, int *, double *, double *, int *), dtpsv_(char *, char *, char *, int *, double *, double *, int *); int wantz, alleig, indeig, valeig; extern int xerbla_(char *, int *), dpptrf_( char *, int *, double *, int *), dspgst_( int *, char *, int *, double *, double *, int *), dspevx_(char *, char *, char *, int *, double *, double *, double *, int *, int *, double *, int *, double *, double *, int *, double *, int *, int *, int *); /* -- LAPACK driver routine (version 3.2) -- */ /* Univ. of Tennessee, Univ. of California Berkeley and NAG Ltd.. */ /* November 2006 */ /* .. Scalar Arguments .. */ /* .. */ /* .. Array Arguments .. */ /* .. */ /* Purpose */ /* ======= */ /* DSPGVX computes selected eigenvalues, and optionally, eigenvectors */ /* of a float 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 storage, and B */ /* is also positive definite. Eigenvalues and eigenvectors can be */ /* selected by specifying either a range of values or a range of indices */ /* for the desired eigenvalues. */ /* 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. */ /* RANGE (input) CHARACTER*1 */ /* = 'A': all eigenvalues will be found. */ /* = 'V': all eigenvalues in the half-open interval (VL,VU] */ /* will be found. */ /* = 'I': the IL-th through IU-th eigenvalues will be found. */ /* UPLO (input) CHARACTER*1 */ /* = 'U': Upper triangle of A and B are stored; */ /* = 'L': Lower triangle of A and B are stored. */ /* N (input) INTEGER */ /* The order of the matrix pencil (A,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. */ /* VL (input) DOUBLE PRECISION */ /* VU (input) DOUBLE PRECISION */ /* If RANGE='V', the lower and upper bounds of the interval to */ /* be searched for eigenvalues. VL < VU. */ /* Not referenced if RANGE = 'A' or 'I'. */ /* IL (input) INTEGER */ /* IU (input) INTEGER */ /* If RANGE='I', the indices (in ascending order) of the */ /* smallest and largest eigenvalues to be returned. */ /* 1 <= IL <= IU <= N, if N > 0; IL = 1 and IU = 0 if N = 0. */ /* Not referenced if RANGE = 'A' or 'V'. */ /* ABSTOL (input) DOUBLE PRECISION */ /* The absolute error tolerance for the eigenvalues. */ /* An approximate eigenvalue is accepted as converged */ /* when it is determined to lie in an interval [a,b] */ /* of width less than or equal to */ /* ABSTOL + EPS * MAX( |a|,|b| ) , */ /* where EPS is the machine precision. If ABSTOL is less than */ /* or equal to zero, then EPS*|T| will be used in its place, */ /* where |T| is the 1-norm of the tridiagonal matrix obtained */ /* by reducing A to tridiagonal form. */ /* Eigenvalues will be computed most accurately when ABSTOL is */ /* set to twice the underflow threshold 2*DLAMCH('S'), not zero. */ /* If this routine returns with INFO>0, indicating that some */ /* eigenvectors did not converge, try setting ABSTOL to */ /* 2*DLAMCH('S'). */ /* M (output) INTEGER */ /* The total number of eigenvalues found. 0 <= M <= N. */ /* If RANGE = 'A', M = N, and if RANGE = 'I', M = IU-IL+1. */ /* W (output) DOUBLE PRECISION array, dimension (N) */ /* On normal exit, the first M elements contain the selected */ /* eigenvalues in ascending order. */ /* Z (output) DOUBLE PRECISION array, dimension (LDZ, MAX(1,M)) */ /* If JOBZ = 'N', then Z is not referenced. */ /* If JOBZ = 'V', then if INFO = 0, the first M columns of Z */ /* contain the orthonormal eigenvectors of the matrix A */ /* corresponding to the selected eigenvalues, with the i-th */ /* column of Z holding the eigenvector associated with W(i). */ /* 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 an eigenvector fails to converge, then that column of Z */ /* contains the latest approximation to the eigenvector, and the */ /* index of the eigenvector is returned in IFAIL. */ /* Note: the user must ensure that at least MAX(1,M) columns are */ /* supplied in the array Z; if RANGE = 'V', the exact value of M */ /* is not known in advance and an upper bound must be used. */ /* 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 (8*N) */ /* IWORK (workspace) INTEGER array, dimension (5*N) */ /* IFAIL (output) INTEGER array, dimension (N) */ /* If JOBZ = 'V', then if INFO = 0, the first M elements of */ /* IFAIL are zero. If INFO > 0, then IFAIL contains the */ /* indices of the eigenvectors that failed to converge. */ /* If JOBZ = 'N', then IFAIL is not referenced. */ /* INFO (output) INTEGER */ /* = 0: successful exit */ /* < 0: if INFO = -i, the i-th argument had an illegal value */ /* > 0: DPPTRF or DSPEVX returned an error code: */ /* <= N: if INFO = i, DSPEVX failed to converge; */ /* i eigenvectors failed to converge. Their indices */ /* are stored in array IFAIL. */ /* > 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. */ /* Further Details */ /* =============== */ /* Based on contributions by */ /* Mark Fahey, Department of Mathematics, Univ. of Kentucky, USA */ /* ===================================================================== */ /* .. Local Scalars .. */ /* .. */ /* .. External Functions .. */ /* .. */ /* .. External Subroutines .. */ /* .. */ /* .. Intrinsic Functions .. */ /* .. */ /* .. Executable Statements .. */ /* Test the input parameters. */ /* Parameter adjustments */ --ap; --bp; --w; z_dim1 = *ldz; z_offset = 1 + z_dim1; z__ -= z_offset; --work; --iwork; --ifail; /* Function Body */ upper = lsame_(uplo, "U"); wantz = lsame_(jobz, "V"); alleig = lsame_(range, "A"); valeig = lsame_(range, "V"); indeig = lsame_(range, "I"); *info = 0; if (*itype < 1 || *itype > 3) { *info = -1; } else if (! (wantz || lsame_(jobz, "N"))) { *info = -2; } else if (! (alleig || valeig || indeig)) { *info = -3; } else if (! (upper || lsame_(uplo, "L"))) { *info = -4; } else if (*n < 0) { *info = -5; } else { if (valeig) { if (*n > 0 && *vu <= *vl) { *info = -9; } } else if (indeig) { if (*il < 1) { *info = -10; } else if (*iu < MIN(*n,*il) || *iu > *n) { *info = -11; } } } if (*info == 0) { if (*ldz < 1 || wantz && *ldz < *n) { *info = -16; } } if (*info != 0) { i__1 = -(*info); xerbla_("DSPGVX", &i__1); return 0; } /* Quick return if possible */ *m = 0; 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); dspevx_(jobz, range, uplo, n, &ap[1], vl, vu, il, iu, abstol, m, &w[1], & z__[z_offset], ldz, &work[1], &iwork[1], &ifail[1], info); if (wantz) { /* Backtransform eigenvectors to the original problem. */ if (*info > 0) { *m = *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 = *m; for (j = 1; j <= i__1; ++j) { dtpsv_(uplo, trans, "Non-unit", n, &bp[1], &z__[j * z_dim1 + 1], &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 = *m; for (j = 1; j <= i__1; ++j) { dtpmv_(uplo, trans, "Non-unit", n, &bp[1], &z__[j * z_dim1 + 1], &c__1); /* L20: */ } } } return 0; /* End of DSPGVX */ } /* dspgvx_ */
void mexFunction(int nlhs, mxArray *plhs[], int nrhs, const mxArray *prhs[]) { /* Declare Variables */ char *ch1 = "V", *ch2 = "I", *ch3 = "L"; void *A, *W, *Z, *work; double ABSTOLD = 0.0, VLD = 0.0, VUD = 0.0; float ABSTOLF = 0.0, VLF = 0.0, VUF = 0.0; #ifdef MWSIZE mwSize N, *iwork, *ifail, info = 0, numElem, optional, IL, IU, M, num_eigs, isDouble = 1; #else int N, *iwork, *ifail, info = 0, numElem, optional, IL, IU, M, num_eigs, isDouble = 1; #endif /****** Do Error check *************/ if (nrhs != 4) { mexErrMsgTxt("icatb_eig_symm_sel function accepts four input arguments.\nThe usage of the function is [eigen_vectors, eigen_values] = icatb_eig_symm_sel(A, N, num_eigs, opt);\nwhere A is the lower triangular matrix without zeros entered as a vector, N is the original dimension, num_eigs is the number of eigen values and opt is parameter to operate on copy of the matrix or the original array."); } #ifdef MWSIZE /* Inputs Matrix (A), order (N), number of eigen values (num_eigs), parameter (opt) to operate on copy or original matrix*/ numElem = (mwSize) mxGetNumberOfElements(prhs[0]); N = (mwSize) mxGetScalar(prhs[1]); num_eigs = (mwSize) mxGetScalar(prhs[2]); /* Parameter for using the copy or original array to do operations*/ optional = (mwSize) mxGetScalar(prhs[3]); #else numElem = (int) mxGetNumberOfElements(prhs[0]); N = (int) mxGetScalar(prhs[1]); num_eigs = (int) mxGetScalar(prhs[2]); optional = (int) mxGetScalar(prhs[3]); #endif if (numElem != (N*(N + 1)/2)) { mexErrMsgTxt("Number of elements of input matrix (A) must be equal to N*(N+1)/2"); } if (num_eigs > N) { mexErrMsgTxt("Number of eigen values desired is greater than the number of rows of matrix"); } if (nlhs > 2) { mexErrMsgTxt("Maximum allowed output arguments is 2."); } /********* End for doing error check *********/ /* Eigen values desired */ IL = N - num_eigs + 1; IU = N; /* Check isdouble */ if (mxIsDouble(prhs[0])) { isDouble = 1; if (optional == 1) { A = (void *) mxCalloc(numElem, sizeof(double)); memcpy(A, mxGetData(prhs[0]), numElem*sizeof(double)); } else { A = mxGetData(prhs[0]); } A = (double *) A; /* Pointer to work */ work = (double *) mxCalloc(8*N, sizeof(double)); /* Pointer to eigen vectors */ plhs[0] = mxCreateDoubleMatrix(N, num_eigs, mxREAL); Z = mxGetPr(plhs[0]); /* Pointer to eigen values */ plhs[1] = mxCreateDoubleMatrix(1, num_eigs, mxREAL); W = mxGetPr(plhs[1]); /* Tolerance */ ABSTOLD = mxGetEps(); } else { isDouble = 0; if (optional == 1) { A = (void *) mxCalloc(numElem, sizeof(float)); memcpy(A, mxGetData(prhs[0]), numElem*sizeof(float)); } else { A = mxGetData(prhs[0]); } A = (float *) A; /* Pointer to work */ work = (float *) mxCalloc(8*N, sizeof(float)); /* Pointer to eigen vectors */ plhs[0] = mxCreateNumericMatrix(N, num_eigs, mxSINGLE_CLASS, mxREAL); Z = (float *) mxGetData(plhs[0]); /* Pointer to eigen values */ plhs[1] = mxCreateNumericMatrix(1, num_eigs, mxSINGLE_CLASS, mxREAL); W = (float *) mxGetData(plhs[1]); ABSTOLF = (float) mxGetEps(); } #ifdef MWSIZE /* Pointer to iwork */ iwork = (mwSize *) mxCalloc(5*N, sizeof(mwSize)); /* Pointer to ifail */ ifail = (mwSize *) mxCalloc(N, sizeof(mwSize)); #else /* Pointer to iwork */ iwork = (int *) mxCalloc(5*N, sizeof(int)); /* Pointer to ifail */ ifail = (int *) mxCalloc(N, sizeof(int)); #endif /* Call subroutine to find eigen values and vectors */ #ifdef PC /* Handle Windows */ if (isDouble == 1) { /* Double precision */ dspevx(ch1, ch2, ch3, &N, A, &VLD, &VUD, &IL, &IU, &ABSTOLD, &M, W, Z, &N, work, iwork, ifail, &info); } else { /* Use single precision routine */ #ifdef SINGLE_SUPPORT sspevx(ch1, ch2, ch3, &N, A, &VLF, &VUF, &IL, &IU, &ABSTOLF, &M, W, Z, &N, work, iwork, ifail, &info); #else mexErrMsgTxt("Error executing sspevx function on this MATLAB version.\nUse double precision to solve eigen value problem"); #endif } /* End for handling Windows */ #else /* Handle other OS */ if (isDouble == 1) { dspevx_(ch1, ch2, ch3, &N, A, &VLD, &VUD, &IL, &IU, &ABSTOLD, &M, W, Z, &N, work, iwork, ifail, &info); } else { /* Use single precision routine */ #ifdef SINGLE_SUPPORT sspevx_(ch1, ch2, ch3, &N, A, &VLF, &VUF, &IL, &IU, &ABSTOLF, &M, W, Z, &N, work, iwork, ifail, &info); #else mexErrMsgTxt("Error executing sspevx_ function on this MATLAB version.\nUse double precision to solve eigen value problem"); #endif } /* End for handling other OS */ #endif /* End for calling subroutine to find eigen values and vectors */ if (M != num_eigs) { mexPrintf("%s%d\t%s%d\n", "No. of eigen values estimated: ", M, "No. of eigen values desired: ", num_eigs); mexErrMsgTxt("Error executing dspevx function\n"); } if (info == 1) { mexErrMsgTxt("Error executing dspevx/sspevx function."); } /* Free memory */ if (optional == 1) { mxFree(A); } mxFree(work); mxFree(iwork); mxFree(ifail); }