/* pdnmesh - a 2D finite element solver Copyright (C) 2001-2005 Sarod Yatawatta This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA $Id: eig.c,v 1.10 2005/02/11 18:11:19 sarod Exp $ */ /* aigenvalue routines for symmetric matrices, storage is reduced */ #include #include /* for sqrt */ #include /* for calloc */ #include /* for memcpy */ #include "types.h" MY_DOUBLE *eig_array; /* array to store solved eigenvalues */ /* macros to access elements in matrices */ /* all these macros assume (i,j) within [0,m-1] */ /* Upper Hessenberg form * is represented by shifting all rows to the left so no zeros * are present */ /* get the (i,j) element from upper Hessenberg A- m by m */ #define eH(A,i,j,m) \ ((((i)==0)||((i)==1))?A[(i)][(j)]:\ ((j)<(i)-1?0:A[(i)][(j)-(i)+1])) /* tridiagonal form * is represented by shifting all rows to the left until no zero appears */ /* maximum row length is 3 */ #define eT(A,i,j,m) \ ((((j)>(i)+1)||((j)<(i)-1))?0:\ (((i)==0)?A[(i)][(j)]:A[(i)][(j)-(i)+1])) /* upper tridiagonal form */ /* is represented by shifting all row to left until no zero appears */ /* maximum row length is 3 */ #define eUT(A,i,j,m) \ ((((j)<(i))||((j)>(i)+2))?0:\ ((i)==0?A[(i)][(j)]:A[(i)][(j)-(i)+1])) static void convert_to_hessenberg(MY_DOUBLE **A, MY_DOUBLE **B, int m) { /* convert matrix A (m by m), symmetric to * tridiagonal form B. * structure of A - m by m square * structure if B - tri diagonal * both matrices modified */ int i,j,k; MY_DOUBLE *v,*u; /* vectors */ MY_DOUBLE norm; v =(MY_DOUBLE*)calloc(m-1,sizeof(MY_DOUBLE)); if ( v == 0 ) { fprintf(stderr,"%s: %d: no free memory",__FILE__,__LINE__); exit(1); } u =(MY_DOUBLE*)calloc(m,sizeof(MY_DOUBLE)); if ( u == 0 ) { fprintf(stderr,"%s: %d: no free memory",__FILE__,__LINE__); exit(1); } /* main loop */ for (k=0; k < m; k++ ) { /* copy vector */ norm =0; for ( i=0; i 0 ) v[0] += sqrt(norm); else v[0] -= sqrt(norm); /* find the new norm */ norm -= u[0]*u[0]; norm += v[0]*v[0]; norm = sqrt(norm); /* make vector v unit norm */ for (i=0; i=0?sqrt(norm):-sqrt(norm)); /* again calculate norm of v, not u */ norm +=v[0]*v[0]-u[0]*u[0]; norm=sqrt(norm); v[0]/=norm; /* v_k=v_k/||v_k|| */ v[1]=u[1]/norm; /* all other elements are zero */ #ifdef DEBUG printf("qr: Householder vector for col %d\n",k); for (i=0;i=0; k--) { /* retrieve v_k */ memset((void*)v,0,sizeof(MY_DOUBLE)*(size_t)(m-k)); v[0]=scratch[0][k]; v[1]=scratch[1][k]; #ifdef DEBUG printf("using householder %d\n",k); for (i=0;i=0 ) { mu=sqrtf((float)mu); } v[0]=0.5*(H[0][0]+H[1][1]+mu); v[1]=0.5*(H[0][0]+H[1][1]-mu); if ( ABS(v[0])=k) with max |U_ik| */ i=k;max=ABS(A[v[i]][k]); for (j=k;jmax){ i=j;max=ABS(A[v[i]][k]); } } /* interchange rows */ /* U_k,k:m-1 <-> U_i,k:m-1 and * L_k,0:k-1 <-> L_i,0:k-1 */ /* instead we interchange the row index */ j=v[k]; v[k]=v[i]; v[i]=j; /* now U_k,k should have the max value from column k * if U_k,k is zero matrix is singular * hence substitude a small value*/ if (A[v[k]][k]==0){ printf("***: warning: matrix is singular\n"); A[v[k]][k]=0.0000001; } for (j=k+1;j=0;i--) { max=0; for (j=i+1;j=m-n;en--) { /* initial guess */ memset((void*)vec,0,(size_t)m*sizeof(MY_DOUBLE)); vec[0]=1; /* start with unit vector */ for (j=0; j=m-n;en--) { /* copy eigenvalue to output */ ev[i++]=v[en]; } for(i=0;i