/* ================================================================== trivec - Matlab CMEX program Find eigenvectors of tridiagonal quasi-symmetric matrix eigenvectors = trivec(eigenvalues,diag,off_diag); Input: eigenvalues - find vectors for each of these values. diag - the main diagonal of a quasi-symmetric tridiagonal matrix. off_diag- (Optional) the product of the off diagonals. defaults to all ones. Output: eigenvectors - SET TO 0 if routine did not converge. ------------------------------------------------------------------ Uses inverse iteration to find eigenvectors. This is not efficient unless we are looking for less than 25% of the total number of vectors. Calls C routine sinvitC() Author: Robert Bernecky Date : 6/10/94 ================================================================== */ #include #include #include "cmex.h" /* eigenvectors = trivec(eigenvalues,diag,off_diag); */ #define EV prhs[0] #define Dm prhs[1] #define Em prhs[2] #define EVS plhs[0] #define FALSE (0) #define TRUE (1) int sinvitC(); /* --------------------------------------------------------------- eigenvectors = trivec(eigenvalues,diag,off_diag); --------------------------------------------------------------- */ user_fcn (nlhs,plhs,nrhs,prhs) int nlhs, nrhs; Matrix *plhs[], *prhs[]; { double *pd, *ofd, *offdiag, *eigval; int i, eig_ct, all_ones=FALSE, N, stat; if (nrhs < 2) mex_error("Function trivec must have at least two input arguments"); if (EV->pi != NULL) mex_error("First argument of function trivec must be real"); if (((Dm->m == 1) && (Dm->n == 1)) || (Dm->pi != NULL)) mex_error("2nd argument of function trivec must be a real vector"); if (nrhs >= 3) { if (((Em->m == 1) && (Em->n == 1)) || (Em->pi != NULL)) mex_error("3rd argument of function trivec must be a real vector"); } else all_ones= TRUE; eig_ct= (int)(EV->m * EV->n); N= (int) (Dm->m * Dm->n); /* size of main diagonal */ pd= offdiag= (double *) mex_calloc(N, sizeof(double)); if (all_ones) for(i=0;ipr;ipr; eigval= (double *) EV->pr; for(i=0;ipr,offdiag,*eigval,(pd+i*N)); if (stat<0) printf("trivec did not converge for eigenvalue %d=%f\n",i,*eigval); } /* cleanup */ mex_free(offdiag); } /* ================================================================= sinvitC Finds the eigenvector of a tridiagonal quasi-symmetric matrix corresponding to the given eigenvalue, using inverse iteration. Input N order of the matrix Adiag main diagonal of tridiagonal, symmetric matrix subDiag subdiagonal elements. subDiag[0] is set to 0. These must be the sqrt of the products. eigVal eigenvalue Output: eigVec the eigenvector corresponding to eigVal sinvitC return 0 normally, -1 if eigenvector fails to converge in 5 iterations. ------------------------------------------------------------------ This routine is a modified version of TINVIT in EISPACK. Specialized to the case of finding one eigenvector. WARNING: The modifications have not been done extremely carefully. Very probably this routine will fail for certain difficult cases for which the original TINVIT would not; for instance, problems with nearly degenerate eigenvectors or separable problems. See ALGOL procedure TRISTURM by Peters and Wilkinson, "Handbook for Auto. Comp., Vol. II Linear Algebra 418-439. (1971) Revision History 7/1/85 Michael Porter mod'f TINVIT to fortran 77 6/4/94 W. Robert Bernecky C version suitable for matlab ================================================================= */ #define macheps (1.0e-12) /* a touchy parameter */ int sinvitC(N, Adiag, subDiag, eigVal, eigVec) int N; double Adiag[], subDiag[], eigVal, *eigVec; { int i,iter,N1; double eps3, eps4, norm, U, UK, XU, V; double *pRV1, *RV1, *pRV2, *RV2, *pRV3, *RV3; double *pRV4, *RV4, *pRV6, *RV6; double *D, *E; /* allocate some temporary arrays */ RV1= pRV1= (double *) malloc(N*sizeof(double)); RV2= pRV2= (double *) malloc(N*sizeof(double)); RV3= pRV3= (double *) malloc(N*sizeof(double)); RV4= pRV4= (double *) malloc(N*sizeof(double)); RV6= pRV6= (double *) malloc(N*sizeof(double)); /* compute (infinity) norm of matrix */ subDiag[0]=0.0; for(i=0,D=Adiag,E=subDiag,norm=0.0;i=fabs(U)) { *(++RV4) = XU= U/ *E; *RV1= *E; *RV2= *D - eigVal; *RV3= 0.0; if (i Nth element */ /* ***** Main loop of inverse iteration ***** */ for(i=0;i=5) { for(i=0;i