Mercurial > hg > x
diff matrix.cpp @ 2:fc19d45615d1
* Make all file names lower-case to avoid case ambiguity
(some includes differed in case from the filenames they were
trying to include). Also replace MinGW-specific mem.h with
string.h
author | Chris Cannam |
---|---|
date | Tue, 05 Oct 2010 11:04:40 +0100 |
parents | Matrix.cpp@6422640a802f |
children | 5f3c32dc6e17 |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/matrix.cpp Tue Oct 05 11:04:40 2010 +0100 @@ -0,0 +1,2245 @@ +//--------------------------------------------------------------------------- +#include <math.h> +#include <memory.h> +#include "matrix.h" +//--------------------------------------------------------------------------- +/* + function BalanceSim: applies a similarity transformation to matrix a so that a is "balanced". This is + used by various eigenvalue evaluation routines. + + In: matrix A[n][n] + Out: balanced matrix a + + No return value. +*/ +void BalanceSim(int n, double** A) +{ + if (n<2) return; + const int radix=2; + double sqrdx; + sqrdx=radix*radix; + bool finish=false; + while (!finish) + { + finish=true; + for (int i=0; i<n; i++) + { + double s, sr=0, sc=0, ar, ac; + for (int j=0; j<n; j++) + if (j!=i) + { + sc+=fabs(A[j][i]); + sr+=fabs(A[i][j]); + } + if (sc!=0 && sr!=0) + { + ar=sr/radix; + ac=1.0; + s=sr+sc; + while (sc<ar) + { + ac*=radix; + sc*=sqrdx; + } + ar=sr*radix; + while (sc>ar) + { + ac/=radix; + sc/=sqrdx; + } + } + if ((sc+sr)/ac<0.95*s) + { + finish=false; + ar=1.0/ac; + for (int j=0; j<n; j++) A[i][j]*=ar; + for (int j=0; j<n; j++) A[j][i]*=ac; + } + } + } +}//BalanceSim + +//--------------------------------------------------------------------------- +/* + function Choleski: Choleski factorization A=LL', where L is lower triangular. The symmetric matrix + A[N][N] is positive definite iff A can be factored as LL', where L is lower triangular with nonzero + diagonl entries. + + In: matrix A[N][N] + Out: mstrix L[N][N]. + + Returns 0 if successful. On return content of matrix a is not changed. +*/ +int Choleski(int N, double** L, double** A) +{ + if (A[0][0]==0) return 1; + L[0][0]=sqrt(A[0][0]); + memset(&L[0][1], 0, sizeof(double)*(N-1)); + for (int j=1; j<N; j++) L[j][0]=A[j][0]/L[0][0]; + for (int i=1; i<N-1; i++) + { + L[i][i]=A[i][i]; for (int k=0; k<i; k++) L[i][i]-=L[i][k]*L[i][k]; L[i][i]=sqrt(L[i][i]); + if (L[i][i]==0) return 1; + for (int j=i+1; j<N; j++) + { + L[j][i]=A[j][i]; for (int k=0; k<i; k++) L[j][i]-=L[j][k]*L[i][k]; L[j][i]/=L[i][i]; + } + memset(&L[i][i+1], 0, sizeof(double)*(N-1-i)); + } + L[N-1][N-1]=A[N-1][N-1]; for (int k=0; k<N-1; k++) L[N-1][N-1]-=L[N-1][k]*L[N-1][k]; L[N-1][N-1]=sqrt(L[N-1][N-1]); + return 0; +}//Choleski + +//--------------------------------------------------------------------------- +//matrix duplication routines + +/* + function Copy: duplicate the matrix A as matrix Z. + + In: matrix A[M][N] + Out: matrix Z[M][N] + + Returns pointer to Z. Z is created anew if Z=0 is supplied on start. +*/ +double** Copy(int M, int N, double** Z, double** A, MList* List) +{ + if (!Z) {Allocate2(double, M, N, Z); if (List) List->Add(Z, 2);} + int sizeN=sizeof(double)*N; + for (int m=0; m<M; m++) memcpy(Z[m], A[m], sizeN); + return Z; +}//Copy +//complex version +cdouble** Copy(int M, int N, cdouble** Z, cdouble** A, MList* List) +{ + if (!Z) {Allocate2(cdouble, M, N, Z); if (List) List->Add(Z, 2);} + int sizeN=sizeof(cdouble)*N; + for (int m=0; m<M; m++) memcpy(Z[m], A[m], sizeN); + return Z; +}//Copy +//version without specifying pre-allocated z +double** Copy(int M, int N, double** A, MList* List){return Copy(M, N, 0, A, List);} +cdouble** Copy(int M, int N, cdouble** A, MList* List){return Copy(M, N, 0, A, List);} +//for square matrices +double** Copy(int N, double** Z, double ** A, MList* List){return Copy(N, N, Z, A, List);} +double** Copy(int N, double** A, MList* List){return Copy(N, N, 0, A, List);} +cdouble** Copy(int N, cdouble** Z, cdouble** A, MList* List){return Copy(N, N, Z, A, List);} +cdouble** Copy(int N, cdouble** A, MList* List){return Copy(N, N, 0, A, List);} + +//--------------------------------------------------------------------------- +//vector duplication routines + +/* + function Copy: duplicating vector a as vector z + + In: vector a[N] + Out: vector z[N] + + Returns pointer to z. z is created anew is z=0 is specified on start. +*/ +double* Copy(int N, double* z, double* a, MList* List) +{ + if (!z){z=new double[N]; if (List) List->Add(z, 1);} + memcpy(z, a, sizeof(double)*N); + return z; +}//Copy +cdouble* Copy(int N, cdouble* z, cdouble* a, MList* List) +{ + if (!z){z=new cdouble[N]; if (List) List->Add(z, 1);} + memcpy(z, a, sizeof(cdouble)*N); + return z; +}//Copy +//version without specifying pre-allocated z +double* Copy(int N, double* a, MList* List){return Copy(N, 0, a, List);} +cdouble* Copy(int N, cdouble* a, MList* List){return Copy(N, 0, a, List);} + +//--------------------------------------------------------------------------- +/* + function det: computes determinant by Gaussian elimination method with column pivoting + + In: matrix A[N][N] + + Returns det(A). On return content of matrix A is unchanged if mode=0. +*/ +double det(int N, double** A, int mode) +{ + int c, p, ip, *rp=new int[N]; for (int i=0; i<N; i++) rp[i]=i; + double m, **b, result=1; + + if (mode==0) + { + int sizeN=sizeof(double)*N; + b=new double*[N]; b[0]=new double[N*N]; for (int i=0; i<N; i++) {b[i]=&b[0][i*N]; memcpy(b[i], A[i], sizeN);} + A=b; + } + + //Gaussian eliminating + for (int i=0; i<N-1; i++) + { + p=i, ip=i+1; + while (ip<N){if (fabs(A[rp[ip]][i])>fabs(A[rp[p]][i])) p=ip; ip++;} + if (A[rp[p]][i]==0) {result=0; goto ret;} + if (p!=i) {c=rp[i]; rp[i]=rp[p]; rp[p]=c; result=-result;} + for (int j=i+1; j<N; j++) + { + m=A[rp[j]][i]/A[rp[i]][i]; + A[rp[j]][i]=0; + for (int k=i+1; k<N; k++) A[rp[j]][k]-=m*A[rp[i]][k]; + } + } + if (A[rp[N-1]][N-1]==0) {result=0; goto ret;} + + for (int i=0; i<N; i++) + result*=A[rp[i]][i]; + +ret: + if (mode==0) {delete[] b[0]; delete[] b;} + delete[] rp; + return result; +}//det +//complex version +cdouble det(int N, cdouble** A, int mode) +{ + int c, p, ip, *rp=new int[N]; for (int i=0; i<N; i++) rp[i]=i; + double mm, mp; + cdouble m, **b, result=1; + + if (mode==0) + { + int sizeN=sizeof(cdouble)*N; + b=new cdouble*[N]; b[0]=new cdouble[N*N]; + for (int i=0; i<N; i++) {b[i]=&b[0][i*N]; memcpy(b[i], A[i], sizeN);} + A=b; + } + + //Gaussian elimination + for (int i=0; i<N-1; i++) + { + p=i, ip=i+1; m=A[rp[p]][i]; mp=~m; + while (ip<N){m=A[rp[ip]][i]; mm=~m; if (mm>mp) mp=mm, p=ip; ip++;} + if (mp==0) {result=0; goto ret;} + if (p!=i) {c=rp[i]; rp[i]=rp[p]; rp[p]=c;} + for (int j=i+1; j<N; j++) + { + m=A[rp[j]][i]/A[rp[i]][i]; + A[rp[j]][i]=0; + for (int k=i+1; k<N; k++) A[rp[j]][k]-=m*A[rp[i]][k]; + } + } + if (operator==(A[rp[N-1]][N-1],0)) {result=0; goto ret;} + + for (int i=0; i<N; i++) result=result*A[rp[i]][i]; +ret: + if (mode==0) {delete[] b[0]; delete[] b;} + delete[] rp; + return result; +}//det + +//--------------------------------------------------------------------------- +/* + function EigPower: power method for solving dominant eigenvalue and eigenvector + + In: matrix A[N][N], initial arbitrary vector x[N]. + Out: eigenvalue l, eigenvector x[N]. + + Returns 0 is successful. Content of matrix A is unchangd on return. Initial x[N] must not be zero. +*/ +int EigPower(int N, double& l, double* x, double** A, double ep, int maxiter) +{ + int k=0; + int p=0; for (int i=1; i<N; i++) if (fabs(x[p])<fabs(x[i])) p=i; + Multiply(N, x, x, 1/x[p]); + double e, ty,te, *y=new double[N]; + + while (k<maxiter) + { + MultiplyXy(N, N, y, A, x); + l=y[p]; + int p=0; for (int i=1; i<N; i++) if (fabs(y[p])<fabs(y[i])) p=i; + if (y[p]==0) {l=0; delete[] y; return 0;} + ty=y[0]/y[p]; e=fabs(x[0]-ty); x[0]=ty; + for (int i=1; i<N; i++) + { + ty=y[i]/y[p]; te=fabs(x[i]-ty); if (e<te) e=te; x[i]=ty; + } + if (e<ep) {delete[] y; return 0;} + k++; + } + delete[] y; return 1; +}//EigPower + +//--------------------------------------------------------------------------- +/* + function EigPowerA: EigPower with Aitken acceleration + + In: matrix A[N][N], initial arbitrary vector x[N]. + Out: eigenvalue l, eigenvector x[N]. + + Returns 0 is successful. Content of matrix A is unchangd on return. Initial x[N] must not be zero. +*/ +int EigPowerA(int N, double& l, double* x, double** A, double ep, int maxiter) +{ + int k=0; + int p=0; for (int i=1; i<N; i++) if (fabs(x[p])<fabs(x[i])) p=i; + Multiply(N, x, x, 1/x[p]); + double m, m0=0, m1=0, e, ty,te, *y=new double[N]; + + while (k<maxiter) + { + MultiplyXy(N, N, y, A, x); + m=y[p]; + int p=0; for (int i=1; i<N; i++) if (fabs(y[p])<fabs(y[i])) p=i; + if (y[p]==0) {l=0; delete[] y; return 0;} + ty=y[0]/y[p]; e=fabs(x[0]-ty); x[0]=ty; + for (int i=1; i<N; i++) + { + ty=y[i]/y[p]; te=fabs(x[i]-ty); if (e<te) e=te; x[i]=ty; + } + if (e<ep && k>2) {l=m0-(m1-m0)*(m1-m0)/(m-2*m1+m0); delete[] y; return 0;} + k++; m0=m1; m1=m; + } + delete[] y; return 1; +}//EigPowerA + +//--------------------------------------------------------------------------- +/* + function EigPowerI: Inverse power method for solving the eigenvalue given an approximate non-zero + eigenvector. + + In: matrix A[N][N], approximate eigenvector x[N]. + Out: eigenvalue l, eigenvector x[N]. + + Returns 0 is successful. Content of matrix A is unchangd on return. Initial x[N] must not be zero. +*/ +int EigPowerI(int N, double& l, double* x, double** A, double ep, int maxiter) +{ + int sizeN=sizeof(double)*N; + double* y=new double[N]; MultiplyXy(N, N, y, A, x); + double q=Inner(N, x, y)/Inner(N, x, x), dt; + double** aa=new double*[N]; aa[0]=new double[N*N]; + for (int i=0; i<N; i++) {aa[i]=&aa[0][i*N]; memcpy(aa[i], A[i], sizeN); aa[i][i]-=q;} + dt=GISCP(N, aa); + if (dt==0) {l=q; delete[] aa[0]; delete[] aa; delete[] y; return 0;} + + int k=0; + int p=0; for (int i=1; i<N; i++) if (fabs(x[p])<fabs(x[i])) p=i; + Multiply(N, x, x, 1/x[p]); + + double m, e, ty, te; + while (k<N) + { + MultiplyXy(N, N, y, aa, x); + m=y[p]; + p=0; for (int i=1; i<N; i++) if (fabs(y[p])<fabs(y[i])) p=i; + ty=y[0]/y[p]; te=x[0]-ty; e=fabs(te); x[0]=ty; + for (int i=1; i<N; i++) + { + ty=y[i]/y[p]; te=fabs(x[i]-ty); if (e<te) e=te; x[i]=ty; + } + if (e<ep) {l=1/m+q; delete[] aa[0]; delete[] aa; delete[] y; return 0;} + } + delete[] aa[0]; delete[] aa; + delete[] y; return 1; +}//EigPowerI + +//--------------------------------------------------------------------------- +/* + function EigPowerS: symmetric power method for solving the dominant eigenvalue with its eigenvector + + In: matrix A[N][N], initial arbitrary vector x[N]. + Out: eigenvalue l, eigenvector x[N]. + + Returns 0 is successful. Content of matrix A is unchangd on return. Initial x[N] must not be zero. +*/ +int EigPowerS(int N, double& l, double* x, double** A, double ep, int maxiter) +{ + int k=0; + Multiply(N, x, x, 1/sqrt(Inner(N, x, x))); + double y2, e, ty, te, *y=new double[N]; + while (k<maxiter) + { + MultiplyXy(N, N, y, A, x); + l=Inner(N, x, y); + y2=sqrt(Inner(N, y, y)); + if (y2==0) {l=0; delete[] y; return 0;} + ty=y[0]/y2; te=x[0]-ty; e=te*te; x[0]=ty; + for (int i=1; i<N; i++) + { + ty=y[i]/y2; te=x[i]-ty; e+=te*te; x[i]=ty; + } + e=sqrt(e); + if (e<ep) {delete[] y; return 0;} + k++; + } + delete[] y; + return 1; +}//EigPowerS + +//--------------------------------------------------------------------------- +/* + function EigPowerWielandt: Wielandt's deflation algorithm for solving a second dominant eigenvalue and + eigenvector (m,u) given the dominant eigenvalue and eigenvector (l,v). + + In: matrix A[N][N], first eigenvalue l with eigenvector v[N] + Out: second eigenvalue m with eigenvector u + + Returns 0 if successful. Content of matrix A is unchangd on return. Initial u[N] must not be zero. +*/ +int EigPowerWielandt(int N, double& m, double* u, double l, double* v, double** A, double ep, int maxiter) +{ + int result; + double** b=new double*[N-1]; b[0]=new double[(N-1)*(N-1)]; for (int i=1; i<N-1; i++) b[i]=&b[0][i*(N-1)]; + double* w=new double[N]; + int i=0; for (int j=1; j<N; j++) if (fabs(v[i])<fabs(v[j])) i=j; + if (i!=0) + for (int k=0; k<i; k++) + for (int j=0; j<i; j++) + b[k][j]=A[k][j]-v[k]*A[i][j]/v[i]; + if (i!=0 && i!=N-1) + for (int k=i; k<N-1; k++) + for (int j=0; j<i; j++) + b[k][j]=A[k+1][j]-v[k+1]*A[i][j]/v[i], b[j][k]=A[j][k+1]-v[j]*A[i][k+1]/v[i]; + if (i!=N-1) + for (int k=i; k<N-1; k++) + for (int j=i; j<N-1; j++) b[k][j]=A[k+1][j+1]-v[k+1]*A[i][j+1]/v[i]; + memcpy(w, u, sizeof(double)*(N-1)); + if ((result=EigPower(N-1, m, w, b, ep, maxiter))==0) + { //* + if (i!=N-1) memmove(&w[i+1], &w[i], sizeof(double)*(N-i-1)); + w[i]=0; + for (int k=0; k<N; k++) u[k]=(m-l)*w[k]+Inner(N, A[i], w)*v[k]/v[i]; //*/ + } + delete[] w; delete[] b[0]; delete[] b; + return result; +}//EigPowerWielandt + +//--------------------------------------------------------------------------- +//NR versions of eigensystem + +/* + function EigenValues: solves for eigenvalues of general system + + In: matrix A[N][N] + Out: eigenvalues ev[N] + + Returns 0 if successful. Content of matrix A is destroyed on return. +*/ +int EigenValues(int N, double** A, cdouble* ev) +{ + BalanceSim(N, A); + Hessenb(N, A); + return QR(N, A, ev); +}//EigenValues + +/* + function EigSym: Solves real symmetric eigensystem A + + In: matrix A[N][N] + Out: eigenvalues d[N], transform matrix Q[N][N], so that diag(d)=Q'AQ, A=Q diag(d) Q', AQ=Q diag(d) + + Returns 0 if successful. Content of matrix A is unchanged on return. +*/ +int EigSym(int N, double** A, double* d, double** Q) +{ + Copy(N, Q, A); + double* t=new double[N]; + HouseHolder(5, Q, d, t); + double result=QL(5, d, t, Q); + delete[] t; + return result; +}//EigSym + +//--------------------------------------------------------------------------- +/* + function GEB: Gaussian elimination with backward substitution for solving linear system Ax=b. + + In: coefficient matrix A[N][N], vector b[N] + Out: vector x[N] + + Returns 0 if successful. Contents of matrix A and vector b are destroyed on return. +*/ +int GEB(int N, double* x, double** A, double* b) +{ + //Gaussian eliminating + int c, p, *rp=new int[N]; for (int i=0; i<N; i++) rp[i]=i; + double m; + for (int i=0; i<N-1; i++) + { + p=i; + while (p<N && A[rp[p]][i]==0) p++; + if (p>=N) {delete[] rp; return 1;} + if (p!=i){c=rp[i]; rp[i]=rp[p]; rp[p]=c;} + for (int j=i+1; j<N; j++) + { + m=A[rp[j]][i]/A[rp[i]][i]; + A[rp[j]][i]=0; + for (int k=i+1; k<N; k++) A[rp[j]][k]-=m*A[rp[i]][k]; + b[rp[j]]-=m*b[rp[i]]; + } + } + if (A[rp[N-1]][N-1]==0) {delete[] rp; return 1;} + else + { + //backward substitution + x[N-1]=b[rp[N-1]]/A[rp[N-1]][N-1]; + for (int i=N-2; i>=0; i--) + { + x[i]=b[rp[i]]; for (int j=i+1; j<N; j++) x[i]-=A[rp[i]][j]*x[j]; x[i]/=A[rp[i]][i]; + } + } + delete[] rp; + return 0; +}//GEB + +//--------------------------------------------------------------------------- +/* + function GESCP: Gaussian elimination with scaled column pivoting for solving linear system Ax=b + + In: matrix A[N][N], vector b[N] + Out: vector x[N] + + Returns 0 is successful. Contents of matrix A and vector b are destroyed on return. +*/ +int GESCP(int N, double* x, double** A, double *b) +{ + int c, p, ip, *rp=new int[N]; + double m, *s=new double[N]; + for (int i=0; i<N; i++) + { + s[i]=fabs(A[i][0]); + for (int j=1; j<N; j++) if (s[i]<fabs(A[i][j])) s[i]=fabs(A[i][j]); + if (s[i]==0) {delete[] s; delete[] rp; return 1;} + rp[i]=i; + } + //Gaussian eliminating + for (int i=0; i<N-1; i++) + { + p=i, ip=i+1; + while (ip<N){if (fabs(A[rp[ip]][i])/s[rp[ip]]>fabs(A[rp[p]][i])/s[rp[p]]) p=ip; ip++;} + if (A[rp[p]][i]==0) {delete[] s; delete[] rp; return 1;} + if (p!=i) {c=rp[i]; rp[i]=rp[p]; rp[p]=c;} + for (int j=i+1; j<N; j++) + { + m=A[rp[j]][i]/A[rp[i]][i]; + A[rp[j]][i]=0; + for (int k=i+1; k<N; k++) A[rp[j]][k]-=m*A[rp[i]][k]; + b[rp[j]]-=m*b[rp[i]]; + } + } + if (A[rp[N-1]][N-1]==0) {delete[] s; delete[] rp; return 1;} + //backward substitution + x[N-1]=b[rp[N-1]]/A[rp[N-1]][N-1]; + for (int i=N-2; i>=0; i--) + { + x[i]=b[rp[i]]; for (int j=i+1; j<N; j++) x[i]-=A[rp[i]][j]*x[j]; x[i]/=A[rp[i]][i]; + } + delete[] s; delete[] rp; + return 0; +}//GESCP + +//--------------------------------------------------------------------------- +/* + function GExL: solves linear system xL=a, L being lower-triangular. This is used in LU factorization + for solving linear systems. + + In: lower-triangular matrix L[N][N], vector a[N] + Out: vector x[N] + + No return value. Contents of matrix L and vector a are unchanged at return. +*/ +void GExL(int N, double* x, double** L, double* a) +{ + for (int n=N-1; n>=0; n--) + { + double xn=a[n]; + for (int m=n+1; m<N; m++) xn-=x[m]*L[m][n]; + x[n]=xn/L[n][n]; + } +}//GExL + +/* + function GExLAdd: solves linear system *L=a, L being lower-triangular, and add the solution * to x[]. + + In: lower-triangular matrix L[N][N], vector a[N] + Out: updated vector x[N] + + No return value. Contents of matrix L and vector a are unchanged at return. +*/ +void GExLAdd(int N, double* x, double** L, double* a) +{ + double* lx=new double[N]; + GExL(N, lx, L, a); + for (int i=0; i<N; i++) x[i]+=lx[i]; + delete[] lx; +}//GExLAdd + +/* + function GExL1: solves linear system xL=(0, 0, ..., 0, a)', L being lower-triangular. + + In: lower-triangular matrix L[N][N], a + Out: vector x[N] + + No return value. Contents of matrix L and vector a are unchanged at return. +*/ +void GExL1(int N, double* x, double** L, double a) +{ + double xn=a; + for (int n=N-1; n>=0; n--) + { + for (int m=n+1; m<N; m++) xn-=x[m]*L[m][n]; + x[n]=xn/L[n][n]; + xn=0; + } +}//GExL1 + +/* + function GExL1Add: solves linear system *L=(0, 0, ..., 0, a)', L being lower-triangular, and add the + solution * to x[]. + + In: lower-triangular matrix L[N][N], vector a + Out: updated vector x[N] + + No return value. Contents of matrix L and vector a are unchanged at return. +*/ +void GExL1Add(int N, double* x, double** L, double a) +{ + double* lx=new double[N]; + GExL1(N, lx, L, a); + for (int i=0; i<N; i++) x[i]+=lx[i]; + delete[] lx; +}//GExL1Add + +//--------------------------------------------------------------------------- +/* + function GICP: matrix inverse using Gaussian elimination with column pivoting: inv(A)->A. + + In: matrix A[N][N] + Out: matrix A[N][N] + + Returns the determinant of the inverse matrix, 0 on failure. +*/ +double GICP(int N, double** A) +{ + int c, p, ip, *rp=new int[N]; for (int i=0; i<N; i++) rp[i]=i; + double m, result=1; + + //Gaussian eliminating + for (int i=0; i<N-1; i++) + { + p=i, ip=i+1; + while (ip<N){if (fabs(A[rp[ip]][i])>fabs(A[rp[p]][i])) p=ip; ip++;} + if (A[rp[p]][i]==0) {delete[] rp; return 0;} + if (p!=i) {c=rp[i]; rp[i]=rp[p]; rp[p]=c; result=-result;} + result/=A[rp[i]][i]; + for (int j=i+1; j<N; j++) + { + m=A[rp[j]][i]/A[rp[i]][i]; + A[rp[j]][i]=-m; + for (int k=i+1; k<N; k++) A[rp[j]][k]-=m*A[rp[i]][k]; + for (int k=0; k<i; k++) A[rp[j]][k]-=m*A[rp[i]][k]; + } + } + if (A[rp[N-1]][N-1]==0) {delete[] rp; return 0;} + result/=A[rp[N-1]][N-1]; + //backward substitution + for (int i=0; i<N-1; i++) + { + m=A[rp[i]][i]; for (int k=0; k<N; k++) A[rp[i]][k]/=m; A[rp[i]][i]=1/m; + for (int j=i+1; j<N; j++) + { + m=A[rp[i]][j]/A[rp[j]][j]; for (int k=0; k<N; k++) A[rp[i]][k]-=A[rp[j]][k]*m; A[rp[i]][j]=-m; + } + } + m=A[rp[N-1]][N-1]; for (int k=0; k<N-1; k++) A[rp[N-1]][k]/=m; A[rp[N-1]][N-1]=1/m; + //recover column and row exchange + double* tm=new double[N]; int sizeN=sizeof(double)*N; + for (int i=0; i<N; i++) { for (int j=0; j<N; j++) tm[rp[j]]=A[i][j]; memcpy(A[i], tm, sizeN); } + for (int j=0; j<N; j++) { for (int i=0; i<N; i++) tm[i]=A[rp[i]][j]; for (int i=0; i<N; i++) A[i][j]=tm[i];} + + delete[] tm; delete[] rp; + return result; +}//GICP +//complex version +cdouble GICP(int N, cdouble** A) +{ + int c, p, ip, *rp=new int[N]; for (int i=0; i<N; i++) rp[i]=i; + cdouble m, result=1; + + //Gaussian eliminating + for (int i=0; i<N-1; i++) + { + p=i, ip=i+1; + while (ip<N){if (~A[rp[ip]][i]>~A[rp[p]][i]) p=ip; ip++;} + if (A[rp[p]][i]==0) {delete[] rp; return 0;} + if (p!=i) {c=rp[i]; rp[i]=rp[p]; rp[p]=c; result=-result;} + result=result/(A[rp[i]][i]); + for (int j=i+1; j<N; j++) + { + m=A[rp[j]][i]/A[rp[i]][i]; + A[rp[j]][i]=-m; + for (int k=i+1; k<N; k++) A[rp[j]][k]-=m*A[rp[i]][k]; + for (int k=0; k<i; k++) A[rp[j]][k]-=m*A[rp[i]][k]; + } + } + if (A[rp[N-1]][N-1]==0) {delete[] rp; return 0;} + result=result/A[rp[N-1]][N-1]; + //backward substitution + for (int i=0; i<N-1; i++) + { + m=A[rp[i]][i]; for (int k=0; k<N; k++) A[rp[i]][k]=A[rp[i]][k]/m; A[rp[i]][i]=cdouble(1)/m; + for (int j=i+1; j<N; j++) + { + m=A[rp[i]][j]/A[rp[j]][j]; for (int k=0; k<N; k++) A[rp[i]][k]-=A[rp[j]][k]*m; A[rp[i]][j]=-m; + } + } + m=A[rp[N-1]][N-1]; for (int k=0; k<N-1; k++) A[rp[N-1]][k]=A[rp[N-1]][k]/m; A[rp[N-1]][N-1]=cdouble(1)/m; + //recover column and row exchange + cdouble* tm=new cdouble[N]; int sizeN=sizeof(cdouble)*N; + for (int i=0; i<N; i++) { for (int j=0; j<N; j++) tm[rp[j]]=A[i][j]; memcpy(A[i], tm, sizeN); } + for (int j=0; j<N; j++) { for (int i=0; i<N; i++) tm[i]=A[rp[i]][j]; for (int i=0; i<N; i++) A[i][j]=tm[i];} + + delete[] tm; delete[] rp; + return result; +}//GICP + +/* + function GICP: wrapper function that does not overwrite the input matrix: inv(A)->X. + + In: matrix A[N][N] + Out: matrix X[N][N] + + Returns the determinant of the inverse matrix, 0 on failure. +*/ +double GICP(int N, double** X, double** A) +{ + Copy(N, X, A); + return GICP(N, X); +}//GICP + +//--------------------------------------------------------------------------- +/* + function GILT: inv(lower trangular of A)->lower trangular of A + + In: matrix A[N][N] + Out: matrix A[N][N] + + Returns the determinant of the lower trangular of A +*/ +double GILT(int N, double** A) +{ + double result=1; + A[0][0]=1/A[0][0]; + for (int i=1; i<N; i++) + { + result*=A[i][i]; + double tmp=1/A[i][i]; + for (int k=0; k<i; k++) A[i][k]*=tmp; A[i][i]=tmp; + for (int j=0; j<i; j++) + { + double tmp2=A[i][j]; + for (int k=0; k<j; k++) A[i][k]-=A[j][k]*tmp2; A[i][j]=-A[j][j]*tmp2; + } + } + return result; +}//GILT + +/* + function GIUT: inv(upper trangular of A)->upper trangular of A + + In: matrix A[N][N] + Out: matrix A[N][N] + + Returns the determinant of the upper trangular of A +*/ +double GIUT(int N, double** A) +{ + double result=1; + A[0][0]=1/A[0][0]; + for (int i=1; i<N; i++) + { + result*=A[i][i]; + double tmp=1/A[i][i]; + for (int k=0; k<i; k++) A[k][i]*=tmp; A[i][i]=tmp; + for (int j=0; j<i; j++) + { + double tmp2=A[j][i]; + for (int k=0; k<j; k++) A[k][i]-=A[k][j]*tmp2; A[j][i]=-A[j][j]*tmp2; + } + } + return result; +}//GIUT + +//--------------------------------------------------------------------------- +/* + function GISCP: matrix inverse using Gaussian elimination w. scaled column pivoting: inv(A)->A. + + In: matrix A[N][N] + Out: matrix A[N][N] + + Returns the determinant of the inverse matrix, 0 on failure. +*/ +double GISCP(int N, double** A) +{ + int c, p, ip, *rp=new int[N]; for (int i=0; i<N; i++) rp[i]=i; + double m, result=1, *s=new double[N]; + + for (int i=0; i<N; i++) + { + s[i]=A[i][0]; + for (int j=1; j<N; j++) if (fabs(s[i])<fabs(A[i][j])) s[i]=A[i][j]; + if (s[i]==0) {delete[] s; delete[] rp; return 0;} + rp[i]=i; + } + + //Gaussian eliminating + for (int i=0; i<N-1; i++) + { + p=i, ip=i+1; + while (ip<N){if (fabs(A[rp[ip]][i]/s[rp[ip]])>fabs(A[rp[p]][i]/s[rp[p]])) p=ip; ip++;} + if (A[rp[p]][i]==0) {delete[] s; delete[] rp; return 0;} + if (p!=i) {c=rp[i]; rp[i]=rp[p]; rp[p]=c; result=-result;} + result/=A[rp[i]][i]; + for (int j=i+1; j<N; j++) + { + m=A[rp[j]][i]/A[rp[i]][i]; + A[rp[j]][i]=-m; + for (int k=i+1; k<N; k++) A[rp[j]][k]-=m*A[rp[i]][k]; + for (int k=0; k<i; k++) A[rp[j]][k]-=m*A[rp[i]][k]; + } + } + if (A[rp[N-1]][N-1]==0) {delete[] s; delete[] rp; return 0;} + result/=A[rp[N-1]][N-1]; + //backward substitution + for (int i=0; i<N-1; i++) + { + m=A[rp[i]][i]; for (int k=0; k<N; k++) A[rp[i]][k]/=m; A[rp[i]][i]=1/m; + for (int j=i+1; j<N; j++) + { + m=A[rp[i]][j]/A[rp[j]][j]; for (int k=0; k<N; k++) A[rp[i]][k]-=A[rp[j]][k]*m; A[rp[i]][j]=-m; + } + } + m=A[rp[N-1]][N-1]; for (int k=0; k<N-1; k++) A[rp[N-1]][k]/=m; A[rp[N-1]][N-1]=1/m; + //recover column and row exchange + double* tm=new double[N]; int sizeN=sizeof(double)*N; + for (int i=0; i<N; i++) { for (int j=0; j<N; j++) tm[rp[j]]=A[i][j]; memcpy(A[i], tm, sizeN); } + for (int j=0; j<N; j++) { for (int i=0; i<N; i++) tm[i]=A[rp[i]][j]; for (int i=0; i<N; i++) A[i][j]=tm[i];} + + delete[] tm; delete[] s; delete[] rp; + return result; +}//GISCP + +/* + function GISCP: wrapper function that does not overwrite input matrix A: inv(A)->X. + + In: matrix A[N][N] + Out: matrix X[N][N] + + Returns the determinant of the inverse matrix, 0 on failure. +*/ +double GISCP(int N, double** X, double** A) +{ + Copy(N, X, A); + return GISCP(N, X); +}//GISCP + +//--------------------------------------------------------------------------- +/* + function GSI: Gaussian-Seidel iterative algorithm for solving linear system Ax=b. Breaks down if any + Aii=0, like the Jocobi method JI(...). + + Gaussian-Seidel iteration is x(k)=(D-L)^(-1)(Ux(k-1)+b), where D is diagonal, L is lower triangular, + U is upper triangular and A=L+D+U. + + In: matrix A[N][N], vector b[N], initial vector x0[N] + Out: vector x0[N] + + Returns 0 is successful. Contents of matrix A and vector b remain unchanged on return. +*/ +int GSI(int N, double* x0, double** A, double* b, double ep, int maxiter) +{ + double e, *x=new double[N]; + int k=0, sizeN=sizeof(double)*N; + while (k<maxiter) + { + for (int i=0; i<N; i++) + { + x[i]=b[i]; + for (int j=0; j<i; j++) x[i]-=A[i][j]*x[j]; + for (int j=i+1; j<N; j++) x[i]-=A[i][j]*x0[j]; + x[i]/=A[i][i]; + } + e=0; for (int j=0; j<N; j++) e+=fabs(x[j]-x0[j]); + memcpy(x0, x, sizeN); + if (e<ep) break; + k++; + } + delete[] x; + if (k>=maxiter) return 1; + return 0; +}//GSI + +//--------------------------------------------------------------------------- +/* + function Hessenb: reducing a square matrix A to upper Hessenberg form + + In: matrix A[N][N] + Out: matrix A[N][N], in upper Hessenberg form + + No return value. +*/ +void Hessenb(int N, double** A) +{ + double x, y; + for (int m=1; m<N-1; m++) + { + x=0; + int i=m; + for (int j=m; j<N; j++) + { + if (fabs(A[j][m-1]) > fabs(x)) + { + x=A[j][m-1]; + i=j; + } + } + if (i!=m) + { + for (int j=m-1; j<N; j++) + { + double tmp=A[i][j]; + A[i][j]=A[m][j]; + A[m][j]=tmp; + } + for (int j=0; j<N; j++) + { + double tmp=A[j][i]; + A[j][i]=A[j][m]; + A[j][m]=tmp; + } + } + if (x!=0) + { + for (i=m+1; i<N; i++) + { + if ((y=A[i][m-1])!=0) + { + y/=x; + A[i][m-1]=0; + for (int j=m; j<N; j++) A[i][j]-=y*A[m][j]; + for (int j=0; j<N; j++) A[j][m]+=y*A[j][i]; + } + } + } + } +}//Hessenb + +//--------------------------------------------------------------------------- +/* + function HouseHolder: house holder method converting a symmetric matrix into a tridiagonal symmetric + matrix, or a non-symmetric matrix into an upper-Hessenberg matrix, using similarity transformation. + + In: matrix A[N][N] + Out: matrix A[N][N] after transformation + + No return value. +*/ +void HouseHolder(int N, double** A) +{ + double q, alf, prod, r2, *v=new double[N], *u=new double[N], *z=new double[N]; + for (int k=0; k<N-2; k++) + { + q=Inner(N-1-k, &A[k][k+1], &A[k][k+1]); + + if (A[k][k+1]==0) alf=sqrt(q); + else alf=-sqrt(q)*A[k+1][k]/fabs(A[k+1][k]); + + r2=alf*(alf-A[k+1][k]); + + v[k]=0; v[k+1]=A[k][k+1]-alf; + memcpy(&v[k+2], &A[k][k+2], sizeof(double)*(N-k-2)); + + for (int j=k; j<N; j++) u[j]=Inner(N-1-k, &A[j][k+1], &v[k+1])/r2; + + prod=Inner(N-1-k, &v[k+1], &u[k+1]); + + MultiAdd(N-k, &z[k], &u[k], &v[k], -prod/2/r2); + + for (int l=k+1; l<N-1; l++) + { + for (int j=l+1; j<N; j++) A[l][j]=A[j][l]=A[j][l]-v[l]*z[j]-v[j]*z[l]; + A[l][l]=A[l][l]-2*v[l]*z[l]; + } + + A[N-1][N-1]=A[N-1][N-1]-2*v[N-1]*z[N-1]; + + for (int j=k+2; j<N; j++) A[k][j]=A[j][k]=0; + + A[k][k+1]=A[k+1][k]=A[k+1][k]-v[k+1]*z[k]; + } + delete[] u; delete[] v; delete[] z; +}//HouseHolder + +/* + function HouseHolder: house holder transformation T=Q'AQ or A=QTQ', where T is tridiagonal and Q is + unitary i.e. QQ'=I. + + In: matrix A[N][N] + Out: matrix tridiagonal matrix T[N][N] and unitary matrix Q[N][N] + + No return value. Identical A and T allowed. Content of matrix A is unchanged if A!=T. +*/ +void HouseHolder(int N, double** T, double** Q, double** A) +{ + double g, alf, prod, r2, *v=new double[N], *u=new double[N], *z=new double[N]; + int sizeN=sizeof(double)*N; + if (T!=A) for (int i=0; i<N; i++) memcpy(T[i], A[i], sizeN); + for (int i=0; i<N; i++) {memset(Q[i], 0, sizeN); Q[i][i]=1;} + for (int k=0; k<N-2; k++) + { + g=Inner(N-1-k, &T[k][k+1], &T[k][k+1]); + + if (T[k][k+1]==0) alf=sqrt(g); + else alf=-sqrt(g)*T[k+1][k]/fabs(T[k+1][k]); + + r2=alf*(alf-T[k+1][k]); + + v[k]=0; v[k+1]=T[k][k+1]-alf; + memcpy(&v[k+2], &T[k][k+2], sizeof(double)*(N-k-2)); + + for (int j=k; j<N; j++) u[j]=Inner(N-1-k, &T[j][k+1], &v[k+1])/r2; + + prod=Inner(N-1-k, &v[k+1], &u[k+1]); + + MultiAdd(N-k, &z[k], &u[k], &v[k], -prod/2/r2); + + for (int l=k+1; l<N-1; l++) + { + for (int j=l+1; j<N; j++) T[l][j]=T[j][l]=T[j][l]-v[l]*z[j]-v[j]*z[l]; + T[l][l]=T[l][l]-2*v[l]*z[l]; + } + + T[N-1][N-1]=T[N-1][N-1]-2*v[N-1]*z[N-1]; + + for (int j=k+2; j<N; j++) T[k][j]=T[j][k]=0; + + T[k][k+1]=T[k+1][k]=T[k+1][k]-v[k+1]*z[k]; + + for (int i=0; i<N; i++) + MultiAdd(N-k, &Q[i][k], &Q[i][k], &v[k], -Inner(N-k, &Q[i][k], &v[k])/r2); + } + delete[] u; delete[] v; delete[] z; +}//HouseHolder + +/* + function HouseHolder: nr version of householder method for transforming symmetric matrix A to QTQ', + where T is tridiagonal and Q is orthonormal. + + In: matrix A[N][N] + Out: A[N][N]: now containing Q + d[N]: containing diagonal elements of T + sd[N]: containing subdiagonal elements of T as sd[1:N-1]. + + No return value. +*/ +void HouseHolder(int N, double **A, double* d, double* sd) +{ + for (int i=N-1; i>=1; i--) + { + int l=i-1; + double h=0, scale=0; + if (l>0) + { + for (int k=0; k<=l; k++) scale+=fabs(A[i][k]); + if (scale==0.0) sd[i]=A[i][l]; + else + { + for (int k=0; k<=l; k++) + { + A[i][k]/=scale; + h+=A[i][k]*A[i][k]; + } + double f=A[i][l]; + double g=(f>=0?-sqrt(h): sqrt(h)); + sd[i]=scale*g; + h-=f*g; + A[i][l]=f-g; + f=0; + for (int j=0; j<=l; j++) + { + A[j][i]=A[i][j]/h; + g=0; + for (int k=0; k<=j; k++) g+=A[j][k]*A[i][k]; + for (int k=j+1; k<=l; k++) g+=A[k][j]*A[i][k]; + sd[j]=g/h; + f+=sd[j]*A[i][j]; + } + double hh=f/(h+h); + for (int j=0; j<=l; j++) + { + f=A[i][j]; + sd[j]=g=sd[j]-hh*f; + for (int k=0; k<=j; k++) A[j][k]-=(f*sd[k]+g*A[i][k]); + } + } + } + else + sd[i]=A[i][l]; + d[i]=h; + } + + d[0]=sd[0]=0; + + for (int i=0; i<N; i++) + { + int l=i-1; + if (d[i]) + { + for (int j=0; j<=l; j++) + { + double g=0.0; + for (int k=0; k<=l; k++) g+=A[i][k]*A[k][j]; + for (int k=0; k<=l; k++) A[k][j]-=g*A[k][i]; + } + } + d[i]=A[i][i]; + A[i][i]=1.0; + for (int j=0; j<=l; j++) A[j][i]=A[i][j]=0.0; + } +}//HouseHolder + +//--------------------------------------------------------------------------- +/* + function Inner: inner product z=y'x + + In: vectors x[N], y[N] + + Returns inner product of x and y. +*/ +double Inner(int N, double* x, double* y) +{ + double result=0; + for (int i=0; i<N; i++) result+=x[i]*y[i]; + return result; +}//Inner +//complex versions +cdouble Inner(int N, double* x, cdouble* y) +{ + cdouble result=0; + for (int i=0; i<N; i++) result+=x[i]**y[i]; + return result; +}//Inner +cdouble Inner(int N, cdouble* x, cdouble* y) +{ + cdouble result=0; + for (int i=0; i<N; i++) result+=x[i]^y[i]; + return result; +}//Inner +cdouble Inner(int N, cfloat* x, cdouble* y) +{ + cdouble result=0; + for (int i=0; i<N; i++) result+=x[i]^y[i]; + return result; +}//Inner +cfloat Inner(int N, cfloat* x, cfloat* y) +{ + cfloat result=0; + for (int i=0; i<N; i++) result+=x[i]^y[i]; + return result; +}//Inner + +/* + function Inner: inner product z=tr(Y'X) + + In: matrices X[M][N], Y[M][N] + + Returns inner product of X and Y. +*/ +double Inner(int M, int N, double** X, double** Y) +{ + double result=0; + for (int m=0; m<M; m++) for (int n=0; n<N; n++) result+=X[m][n]*Y[m][n]; + return result; +}//Inner + +//--------------------------------------------------------------------------- +/* + function JI: Jacobi interative algorithm for solving linear system Ax=b Breaks down if A[i][i]=0 for + any i. Reorder A so that this does not happen. + + Jacobi iteration is x(k)=D^(-1)((L+U)x(k-1)+b), D is diagonal, L is lower triangular, U is upper + triangular and A=L+D+U. + + In: matrix A[N][N], vector b[N], initial vector x0[N] + Out: vector x0[N] + + Returns 0 if successful. Contents of matrix A and vector b are unchanged on return. +*/ +int JI(int N, double* x0, double** A, double* b, double ep, int maxiter) +{ + double e, *x=new double[N]; + int k=0, sizeN=sizeof(double)*N; + while (k<maxiter) + { + for (int i=0; i<N; i++) + { + x[i]=b[i]; for (int j=0; j<N; j++) if (j!=i) x[i]-=A[i][j]*x0[j]; x[i]=x[i]/A[i][i]; + } + e=0; for (int j=0; j<N; j++) e+=fabs(x[j]-x0[j]); //inf-norm used here + memcpy(x0, x, sizeN); + if (e<ep) break; + k++; + } + delete[] x; + if (k>=maxiter) return 1; + else return 0; +}//JI + +//--------------------------------------------------------------------------- +/* + function LDL: LDL' decomposition A=LDL', where L is lower triangular and D is diagonal identical l and + a allowed. + + The symmetric matrix A is positive definite iff A can be factorized as LDL', where L is lower + triangular with ones on its diagonal and D is diagonal with positive diagonal entries. + + If a symmetric matrix A can be reduced by Gaussian elimination without row interchanges, then it can + be factored into LDL', where L is lower triangular with ones on its diagonal and D is diagonal with + non-zero diagonal entries. + + In: matrix A[N][N] + Out: lower triangular matrix L[N][N], vector d[N] containing diagonal elements of D + + Returns 0 if successful. Content of matrix A is unchanged on return. +*/ +int LDL(int N, double** L, double* d, double** A) +{ + double* v=new double[N]; + + if (A[0][0]==0) {delete[] v; return 1;} + d[0]=A[0][0]; for (int j=1; j<N; j++) L[j][0]=A[j][0]/d[0]; + for (int i=1; i<N; i++) + { + for (int j=0; j<i; j++) v[j]=L[i][j]*d[j]; + d[i]=A[i][i]; for (int j=0; j<i; j++) d[i]-=L[i][j]*v[j]; + if (d[i]==0) {delete[] v; return 1;} + for (int j=i+1; j<N; j++) + { + L[j][i]=A[j][i]; for (int k=0; k<i; k++) L[j][i]-=L[j][k]*v[k]; L[j][i]/=d[i]; + } + } + delete[] v; + + for (int i=0; i<N; i++) {L[i][i]=1; memset(&L[i][i+1], 0, sizeof(double)*(N-1-i));} + return 0; +}//LDL + +//--------------------------------------------------------------------------- +/* + function LQ_GS: LQ decomposition using Gram-Schmidt method + + In: matrix A[M][N], M<=N + Out: matrices L[M][M], Q[M][N] + + No return value. +*/ +void LQ_GS(int M, int N, double** A, double** L, double** Q) +{ + double *u=new double[N]; + for (int m=0; m<M; m++) + { + memset(L[m], 0, sizeof(double)*M); + memcpy(u, A[m], sizeof(double)*N); + for (int k=0; k<m; k++) + { + double ip=0; for (int n=0; n<N; n++) ip+=Q[k][n]*u[n]; + for (int n=0; n<N; n++) u[n]-=ip*Q[k][n]; + L[m][k]=ip; + } + double iu=0; for (int n=0; n<N; n++) iu+=u[n]*u[n]; iu=sqrt(iu); + L[m][m]=iu; iu=1.0/iu; + for (int n=0; n<N; n++) Q[m][n]=u[n]*iu; + } + delete[] u; +}//LQ_GS + +//--------------------------------------------------------------------------- +/* + function LSLinear2: 2-dtage LS solution of A[M][N]x[N][1]=y[M][1], M>=N. Use of this function requires + the submatrix A[N][N] be invertible. + + In: matrix A[M][N], vector y[M], M>=N. + Out: vector x[N]. + + No return value. Contents of matrix A and vector y are unchanged on return. +*/ +void LSLinear2(int M, int N, double* x, double** A, double* y) +{ + double** A1=Copy(N, N, 0, A); + LU(N, x, A1, y); + if (M>N) + { + double** B=&A[N]; + double* Del=MultiplyXy(M-N, N, B, x); + MultiAdd(M-N, Del, Del, &y[N], -1); + double** A2=MultiplyXtX(N, N, A); + MultiplyXtX(N, M-N, A1, B); + MultiAdd(N, N, A2, A2, A1, 1); + double* b2=MultiplyXty(N, M-N, B, Del); + double* dx=new double[N]; + GESCP(N, dx, A2, b2); + MultiAdd(N, x, x, dx, -1); + delete[] dx; + delete[] Del; + delete[] b2; + DeAlloc2(A2); + } + DeAlloc2(A1); +}//LSLinear2 + +//--------------------------------------------------------------------------- +/* + function LU: LU decomposition A=LU, where L is lower triangular with diagonal entries 1 and U is upper + triangular. + + LU is possible if A can be reduced by Gaussian elimination without row interchanges. + + In: matrix A[N][N] + Out: matrices L[N][N] and U[N][N], subject to input values of L and U: + if L euqals NULL, L is not returned + if U equals NULL or A, U is returned in A, s.t. A is modified + if L equals A, L is returned in A, s.t. A is modified + if L equals U, L and U are returned in the same matrix + when L and U are returned in the same matrix, diagonal of L (all 1) is not returned + + Returns 0 if successful. +*/ +int LU(int N, double** L, double** U, double** A) +{ + double* diagl=new double[N]; + for (int i=0; i<N; i++) diagl[i]=1; + + int sizeN=sizeof(double)*N; + if (U==0) U=A; + if (U!=A) for (int i=0; i<N; i++) memcpy(U[i], A[i], sizeN); + int result=LU_Direct(0, N, diagl, U); + if (result==0) + { + if (L!=U) + { + if (L!=0) for (int i=0; i<N; i++) {memcpy(L[i], U[i], sizeof(double)*i); L[i][i]=1; memset(&L[i][i+1], 0, sizeof(double)*(N-i-1));} + for (int i=1; i<N; i++) memset(U[i], 0, sizeof(double)*i); + } + } + delete[] diagl; + return result; +}//LU + +/* + function LU: Solving linear system Ax=y by LU factorization + + In: matrix A[N][N], vector y[N] + Out: x[N] + + No return value. On return A contains its LU factorization (with pivoting, diag mode 1), y remains + unchanged. +*/ +void LU(int N, double* x, double** A, double* y, int* ind) +{ + int parity; + bool allocind=!ind; + if (allocind) ind=new int[N]; + LUCP(A, N, ind, parity, 1); + for (int i=0; i<N; i++) x[i]=y[ind[i]]; + for (int i=0; i<N; i++) + { + for (int j=i+1; j<N; j++) x[j]=x[j]-x[i]*A[j][i]; + } + for (int i=N-1; i>=0; i--) + { + x[i]/=A[i][i]; + for (int j=0; j<i; j++) x[j]=x[j]-x[i]*A[j][i]; + } + if (allocind) delete[] ind; +}//LU + +//--------------------------------------------------------------------------- +/* + LU_DiagL shows the original procedure for calculating A=LU in separate buffers substitute l and u by a + gives the stand-still method LU_Direct(). +*//* +void LU_DiagL(int N, double** l, double* diagl, double** u, double** a) +{ + l[0][0]=diagl[0]; u[0][0]=a[0][0]/l[0][0]; //here to signal failure if l[00]u[00]=0 + for (int j=1; j<N; j++) u[0][j]=a[0][j]/l[0][0], l[j][0]=a[j][0]/u[0][0]; + memset(&l[0][1], 0, sizeof(double)*(N-1)); + for (int i=1; i<N-1; i++) + { + l[i][i]=diagl[i]; + u[i][i]=a[i][i]; for (int k=0; k<i; k++) u[i][i]-=l[i][k]*u[k][i]; u[i][i]/=l[i][i]; //here to signal failure if l[ii]u[ii]=0 + for (int j=i+1; j<N; j++) + { + u[i][j]=a[i][j]; for (int k=0; k<i; k++) u[i][j]-=l[i][k]*u[k][j]; u[i][j]/=l[i][i]; + l[j][i]=a[j][i]; for (int k=0; k<i; k++) l[j][i]-=l[j][k]*u[k][i]; l[j][i]/=u[i][i]; + } + memset(&l[i][i+1], 0, sizeof(double)*(N-1-i)), memset(u[i], 0, sizeof(double)*i); + } + l[N-1][N-1]=diagl[N-1]; + u[N-1][N-1]=a[N-1][N-1]; for (int k=0; k<N-1; k++) u[N-1][N-1]-=l[N-1][k]*u[k][N-1]; u[N-1][N-1]/=l[N-1][N-1]; + memset(u[N-1], 0, sizeof(double)*(N-1)); +} //LU_DiagL*/ + +//--------------------------------------------------------------------------- +/* + function LU_Direct: LU factorization A=LU. + + In: matrix A[N][N], vector diag[N] specifying main diagonal of L or U, according to mode (0=LDiag, + 1=UDiag). + Out: matrix A[N][N] now containing L and U. + + Returns 0 if successful. +*/ +int LU_Direct(int mode, int N, double* diag, double** A) +{ + if (mode==0) + { + if (A[0][0]==0) return 1; + A[0][0]=A[0][0]/diag[0]; + for (int j=1; j<N; j++) A[0][j]=A[0][j]/diag[0], A[j][0]=A[j][0]/A[0][0]; + for (int i=1; i<N-1; i++) + { + for (int k=0; k<i; k++) A[i][i]-=A[i][k]*A[k][i]; A[i][i]/=diag[i]; + if (A[i][i]==0) return 2; + for (int j=i+1; j<N; j++) + { + for (int k=0; k<i; k++) A[i][j]-=A[i][k]*A[k][j]; A[i][j]/=diag[i]; + for (int k=0; k<i; k++) A[j][i]-=A[j][k]*A[k][i]; A[j][i]/=A[i][i]; + } + } + for (int k=0; k<N-1; k++) A[N-1][N-1]-=A[N-1][k]*A[k][N-1]; A[N-1][N-1]/=diag[N-1]; + } + else if (mode==1) + { + A[0][0]=A[0][0]/diag[0]; + if (A[0][0]==0) return 1; + for (int j=1; j<N; j++) A[0][j]=A[0][j]/A[0][0], A[j][0]=A[j][0]/diag[0]; + for (int i=1; i<N-1; i++) + { + for (int k=0; k<i; k++) A[i][i]-=A[i][k]*A[k][i]; A[i][i]/=diag[i]; + if (A[i][i]==0) return 2; + for (int j=i+1; j<N; j++) + { + for (int k=0; k<i; k++) A[i][j]-=A[i][k]*A[k][j]; A[i][j]/=A[i][i]; + for (int k=0; k<i; k++) A[j][i]-=A[j][k]*A[k][i]; A[j][i]/=diag[i]; + } + } + for (int k=0; k<N-1; k++) A[N-1][N-1]-=A[N-1][k]*A[k][N-1]; A[N-1][N-1]/=diag[N-1]; + } + return 0; +}//LU_Direct + +//--------------------------------------------------------------------------- +/* + function LU_PD: LU factorization for pentadiagonal A=LU + + In: pentadiagonal matrix A[N][N] stored in a compact format, i.e. A[i][j]->b[i-j, j] + the main diagonal is b[0][0]~b[0][N-1] + the 1st upper subdiagonal is b[-1][1]~b[-1][N-1] + the 2nd upper subdiagonal is b[-2][2]~b[-2][N-1] + the 1st lower subdiagonal is b[1][0]~b[1][N-2] + the 2nd lower subdiagonal is b[2][0]~b[2][N-3] + + Out: L[N][N] and U[N][N], main diagonal of L being all 1 (probably), stored in a compact format in + b[-2:2][N]. + + Returns 0 if successful. +*/ +int LU_PD(int N, double** b) +{ + if (b[0][0]==0) return 1; + b[1][0]/=b[0][0], b[2][0]/=b[0][0]; + + //i=1, not to double b[*][i-2], b[-2][i] + b[0][1]-=b[1][0]*b[-1][1]; + if (b[0][1]==0) return 2; + b[-1][2]-=b[1][0]*b[-2][2]; + b[1][1]-=b[2][0]*b[-1][1]; + b[1][1]/=b[0][1]; + b[2][1]/=b[0][1]; + + for (int i=2; i<N-2; i++) + { + b[0][i]-=b[2][i-2]*b[-2][i]; + b[0][i]-=b[1][i-1]*b[-1][i]; + if (b[0][i]==0) return 2; + b[-1][i+1]-=b[1][i-1]*b[-2][i+1]; + b[1][i]-=b[2][i-1]*b[-1][i]; + b[1][i]/=b[0][i]; + b[2][i]/=b[0][i]; + } + //i=N-2, not to tough b[2][i] + b[0][N-2]-=b[2][N-4]*b[-2][N-2]; + b[0][N-2]-=b[1][N-3]*b[-1][N-2]; + if (b[0][N-2]==0) return 2; + b[-1][N-1]-=b[1][N-3]*b[-2][N-1]; + b[1][N-2]-=b[2][N-3]*b[-1][N-2]; + b[1][N-2]/=b[0][N-2]; + + b[0][N-1]-=b[2][N-3]*b[-2][N-1]; + b[0][N-1]-=b[1][N-2]*b[-1][N-1]; + return 0; +}//LU_PD + +/* + This old version is kept here as a reference. +*//* +int LU_PD(int N, double** b) +{ + if (b[0][0]==0) return 1; + for (int j=1; j<3; j++) b[j][0]=b[j][0]/b[0][0]; + for (int i=1; i<N-1; i++) + { + for (int k=i-2; k<i; k++) b[0][i]-=b[i-k][k]*b[k-i][i]; + if (b[0][i]==0) return 2; + for (int j=i+1; j<i+3; j++) + { + for (int k=j-2; k<i; k++) b[i-j][j]-=b[i-k][k]*b[k-j][j]; + for (int k=j-2; k<i; k++) b[j-i][i]-=b[j-k][k]*b[k-i][i]; + b[j-i][i]/=b[0][i]; + } + } + for (int k=N-3; k<N-1; k++) b[0][N-1]-=b[N-1-k][k]*b[k-N+1][N-1]; + return 0; +}//LU_PD*/ + +/* + function LU_PD: solve pentadiagonal system Ax=c + + In: pentadiagonal matrix A[N][N] stored in a compact format in b[-2:2][N], vector c[N] + Out: vector c now containing x. + + Returns 0 if successful. On return b is in the LU form. +*/ +int LU_PD(int N, double** b, double* c) +{ + int result=LU_PD(N, b); + if (result==0) + { + //L loop + c[1]=c[1]-b[1][0]*c[0]; + for (int i=2; i<N; i++) + c[i]=c[i]-b[1][i-1]*c[i-1]-b[2][i-2]*c[i-2]; + //U loop + c[N-1]/=b[0][N-1]; + c[N-2]=(c[N-2]-b[-1][N-1]*c[N-1])/b[0][N-2]; + for (int i=N-3; i>=0; i--) + c[i]=(c[i]-b[-1][i+1]*c[i+1]-b[-2][i+2]*c[i+2])/b[0][i]; + } + return result; +}//LU_PD + +//--------------------------------------------------------------------------- +/* + function LUCP: LU decomposition A=LU with column pivoting + + In: matrix A[N][N] + Out: matrix A[N][N] now holding L and U by L_U[i][j]=A[ind[i]][j], where L_U + hosts L and U according to mode: + mode=0: L diag=abs(U diag), U diag as return + mode=1: L diag=1, U diag as return + mode=2: U diag=1, L diag as return + + Returns the determinant of A. +*/ +double LUCP(double **A, int N, int *ind, int &parity, int mode) +{ + double det=1; + parity=1; + + for (int i=0; i<N; i++) ind[i]=i; + double vmax, *norm=new double[N]; //norm[n] is the maxima of row n + for (int i=0; i<N; i++) + { + vmax=fabs(A[i][0]); + double tmp; + for (int j=1; j<N; j++) if ((tmp=fabs(A[i][j]))>vmax) vmax=tmp; + if (vmax==0) { parity=0; goto deletenorm; } //det=0 at this point + norm[i]=1/vmax; + } + + int maxind; + for (int j=0; j<N; j++) + { //Column j + for (int i=0; i<j; i++) + { + //row i, i<j + double tmp=A[i][j]; + for (int k=0; k<i; k++) tmp-=A[i][k]*A[k][j]; + A[i][j]=tmp; + } + for (int i=j; i<N; i++) + { + //row i, i>=j + double tmp=A[i][j]; for (int k=0; k<j; k++) tmp-=A[i][k]*A[k][j]; A[i][j]=tmp; + double tmp2=norm[i]*fabs(tmp); + if (i==j || tmp2>=vmax) maxind=i, vmax=tmp2; + } + if (vmax==0) { parity=0; goto deletenorm; } //pivot being zero + if (j!=maxind) + { + //do column pivoting: switching rows + for (int k=0; k<N; k++) { double tmp=A[maxind][k]; A[maxind][k]=A[j][k]; A[j][k]=tmp; } + parity=-parity; + norm[maxind]=norm[j]; + } + int itmp=ind[j]; ind[j]=ind[maxind]; ind[maxind]=itmp; + if (j!=N-1) + { + double den=1/A[j][j]; + for (int i=j+1; i<N; i++) A[i][j]*=den; + } + det*=A[j][j]; + } //Go back for the next column in the reduction. + + if (mode==0) + { + for (int i=0; i<N-1; i++) + { + double den=sqrt(fabs(A[i][i])); + double iden=1/den; + for (int j=i+1; j<N; j++) A[j][i]*=den, A[i][j]*=iden; + A[i][i]*=iden; + } + A[N-1][N-1]/=sqrt(fabs(A[N-1][N-1])); + } + else if (mode==2) + { + for (int i=0; i<N-1; i++) + { + double den=A[i][i]; + double iden=1/den; + for (int j=i+1; j<N; j++) A[j][i]*=den, A[i][j]*=iden; + } + } + +deletenorm: + delete[] norm; + return det*parity; +}//LUCP + +//--------------------------------------------------------------------------- +/* + function maxind: returns the index of the maximal value of data[from:(to-1)]. + + In: vector data containing at least $to entries. + Out: the index to the maximal entry of data[from:(to-1)] + + Returns the index to the maximal value. +*/ +int maxind(double* data, int from, int to) +{ + int result=from; + for (int i=from+1; i<to; i++) if (data[result]<data[i]) result=i; + return result; +}//maxind + +//--------------------------------------------------------------------------- +/* + macro Multiply_vect: matrix-vector multiplications + + Each expansion of this macro implements two functions named $MULTIPLY that do matrix-vector + multiplication. Functions are named after their exact functions. For example, MultiplyXty() does + multiplication of the transpose of matrix X with vector y, where postfix "t" attched to Y stands for + transpose. Likewise, the postfix "c" stands for conjugate, and "h" stnads for Hermitian (conjugate + transpose). + + Two dimension arguments are needed by each function. The first of the two is the number of entries to + the output vector; the second of the two is the "other" dimension of the matrix multiplier. +*/ +#define Multiply_vect(MULTIPLY, DbZ, DbX, DbY, xx, yy) \ + DbZ* MULTIPLY(int M, int N, DbZ* z, DbX* x, DbY* y, MList* List) \ + { \ + if (!z){z=new DbZ[M]; if (List) List->Add(z, 1);} \ + for (int m=0; m<M; m++){z[m]=0; for (int n=0; n<N; n++) z[m]+=xx*yy;} \ + return z; \ + } \ + DbZ* MULTIPLY(int M, int N, DbX* x, DbY* y, MList* List) \ + { \ + DbZ* z=new DbZ[M]; if (List) List->Add(z, 1); \ + for (int m=0; m<M; m++){z[m]=0; for (int n=0; n<N; n++) z[m]+=xx*yy;} \ + return z; \ + } +//function MultiplyXy: z[M]=x[M][N]y[N], identical z and y NOT ALLOWED +Multiply_vect(MultiplyXy, double, double*, double, x[m][n], y[n]) +Multiply_vect(MultiplyXy, cdouble, cdouble*, cdouble, x[m][n], y[n]) +Multiply_vect(MultiplyXy, cdouble, double*, cdouble, x[m][n], y[n]) +//function MultiplyxY: z[M]=x[N]y[N][M], identical z and x NOT ALLOWED +Multiply_vect(MultiplyxY, double, double, double*, x[n], y[n][m]) +Multiply_vect(MultiplyxY, cdouble, cdouble, cdouble*, x[n], y[n][m]) +//function MultiplyXty: z[M]=xt[M][N]y[N] +Multiply_vect(MultiplyXty, double, double*, double, x[n][m], y[n]) +Multiply_vect(MultiplyXty, cdouble, cdouble*, cdouble, x[n][m], y[n]) +//function MultiplyXhy: z[M]=xh[M][N]y[N] +Multiply_vect(MultiplyXhy, cdouble, cdouble*, cdouble, *x[n][m], y[n]) +//function MultiplyxYt: z[M]=x[N]yt[N][M] +Multiply_vect(MultiplyxYt, double, double, double*, x[n], y[m][n]) +//function MultiplyXcy: z[M]=(x*)[M][N]y[N] +Multiply_vect(MultiplyXcy, cdouble, cdouble*, cdouble, *x[m][n], y[n]) +Multiply_vect(MultiplyXcy, cdouble, cdouble*, cfloat, *x[m][n], y[n]) + +//--------------------------------------------------------------------------- +/* + function Norm1: L-1 norm of a square matrix A + + In: matrix A[N][N] + Out: its L-1 norm + + Returns the L-1 norm. +*/ +double Norm1(int N, double** A) +{ + double result=0, norm; + for (int i=0; i<N; i++) + { + norm=0; for (int j=0; j<N; j++) norm+=fabs(A[i][j]); + if (result<norm) result=norm; + } + return result; +}//Norm1 + +//--------------------------------------------------------------------------- +/* + function QL: QL method for solving tridiagonal symmetric matrix eigenvalue problem. + + In: A[N][N]: tridiagonal symmetric matrix stored in d[N] and sd[] arranged so that d[0:n-1] contains + the diagonal elements of A, sd[0]=0, sd[1:n-1] contains the subdiagonal elements of A. + z[N][N]: pre-transform matrix z[N][N] compatible with HouseHolder() routine. + Out: d[N]: the eigenvalues of A + z[N][N] the eigenvectors of A. + + Returns 0 if successful. sd[] should have storage for at least N+1 entries. +*/ +int QL(int N, double* d, double* sd, double** z) +{ + const int maxiter=30; + for (int i=1; i<N; i++) sd[i-1]=sd[i]; + sd[N]=0.0; + for (int l=0; l<N; l++) + { + int iter=0, m; + do + { + for (m=l; m<N-1; m++) + { + double dd=fabs(d[m])+fabs(d[m+1]); + if (fabs(sd[m])+dd==dd) break; + } + if (m!=l) + { + iter++; + if (iter>=maxiter) return 1; + double g=(d[l+1]-d[l])/(2*sd[l]); + double r=sqrt(g*g+1); + g=d[m]-d[l]+sd[l]/(g+(g>=0?r:-r)); + double s=1, c=1, p=0; + int i; + for (i=m-1; i>=l; i--) + { + double f=s*sd[i], b=c*sd[i]; + sd[i+1]=(r=sqrt(f*f+g*g)); + if (r==0) + { + d[i+1]-=p; + sd[m]=0; + break; + } + s=f/r, c=g/r; + g=d[i+1]-p; + r=(d[i]-g)*s+2.0*c*b; + p=s*r; + d[i+1]=g+p; + g=c*r-b; + for (int k=0; k<N; k++) + { + f=z[k][i+1]; + z[k][i+1]=s*z[k][i]+c*f; + z[k][i]=c*z[k][i]-s*f; + } + } + if (r==0 && i>=l) continue; + d[l]-=p; + sd[l]=g; + sd[m]=0.0; + } + } + while (m!=l); + } + return 0; +}//QL + +//--------------------------------------------------------------------------- +/* + function QR: nr version of QR method for solving upper Hessenberg system A. This is compatible with + Hessenb method. + + In: matrix A[N][N] + Out: vector ev[N] of eigenvalues + + Returns 0 on success. Content of matrix A is destroyed on return. +*/ +int QR(int N, double **A, cdouble* ev) +{ + int n=N, m, l, k, j, iter, i, mmin, maxiter=30; + double **a=A, z, y, x, w, v, u, t=0, s, r, q, p, a1=0; + for (i=0; i<n; i++) for (j=i-1>0?i-1:0; j<n; j++) a1+=fabs(a[i][j]); + n--; + while (n>=0) + { + iter=0; + do + { + for (l=n; l>0; l--) + { + s=fabs(a[l-1][l-1])+fabs(a[l][l]); + if (s==0) s=a1; + if (fabs(a[l][l-1])+s==s) {a[l][l-1]=0; break;} + } + x=a[n][n]; + if (l==n) {ev[n].x=x+t; ev[n--].y=0;} + else + { + y=a[n-1][n-1], w=a[n][n-1]*a[n-1][n]; + if (l==(n-1)) + { + p=0.5*(y-x); + q=p*p+w; + z=sqrt(fabs(q)); + x+=t; + if (q>=0) + { + z=p+(p>=0?z:-z); + ev[n-1].x=ev[n].x=x+z; + if (z) ev[n].x=x-w/z; + ev[n-1].y=ev[n].y=0; + } + else + { + ev[n-1].x=ev[n].x=x+p; + ev[n].y=z; ev[n-1].y=-z; + } + n-=2; + } + else + { + if (iter>=maxiter) return 1; + if (iter%10==9) + { + t+=x; + for (i=0; i<=n; i++) a[i][i]-=x; + s=fabs(a[n][n-1])+fabs(a[n-1][n-2]); + y=x=0.75*s; + w=-0.4375*s*s; + } + iter++; + for (m=n-2; m>=l; m--) + { + z=a[m][m]; + r=x-z; s=y-z; + p=(r*s-w)/a[m+1][m]+a[m][m+1]; q=a[m+1][m+1]-z-r-s; r=a[m+2][m+1]; + s=fabs(p)+fabs(q)+fabs(r); + p/=s; q/=s; r/=s; + if (m==l) break; + u=fabs(a[m][m-1])*(fabs(q)+fabs(r)); + v=fabs(p)*(fabs(a[m-1][m-1])+fabs(z)+fabs(a[m+1][m+1])); + if (u+v==v) break; + } + for (i=m+2; i<=n; i++) + { + a[i][i-2]=0; + if (i!=m+2) a[i][i-3]=0; + } + for (k=m; k<=n-1; k++) + { + if (k!=m) + { + p=a[k][k-1]; + q=a[k+1][k-1]; + r=0; + if (k!=n-1) r=a[k+2][k-1]; + x=fabs(p)+fabs(q)+fabs(r); + if (x!=0) p/=x, q/=x, r/=x; + } + if (p>=0) s=sqrt(p*p+q*q+r*r); + else s=-sqrt(p*p+q*q+r*r); + if (s!=0) + { + if (k==m) + { + if (l!=m) a[k][k-1]=-a[k][k-1]; + } + else a[k][k-1]=-s*x; + p+=s; + x=p/s; y=q/s; z=r/s; q/=p; r/=p; + for (j=k; j<=n; j++) + { + p=a[k][j]+q*a[k+1][j]; + if (k!=n-1) + { + p+=r*a[k+2][j]; + a[k+2][j]-=p*z; + } + a[k+1][j]-=p*y; a[k][j]-=p*x; + } + mmin=n<k+3?n:k+3; + for (i=l; i<=mmin; i++) + { + p=x*a[i][k]+y*a[i][k+1]; + if (k!=(n-1)) + { + p+=z*a[i][k+2]; + a[i][k+2]-=p*r; + } + a[i][k+1]-=p*q; a[i][k]-=p; + } + } + } + } + } + } while (n>l+1); + } + return 0; +}//QR + +/* + function QR_GS: QR decomposition A=QR using Gram-Schmidt method + + In: matrix A[M][N], M>=N + Out: Q[M][N], R[N][N] + + No return value. +*/ +void QR_GS(int M, int N, double** A, double** Q, double** R) +{ + double *u=new double[M]; + for (int n=0; n<N; n++) + { + memset(R[n], 0, sizeof(double)*N); + for (int m=0; m<M; m++) u[m]=A[m][n]; + for (int k=0; k<n; k++) + { + double ip=0; for (int m=0; m<M; m++) ip+=u[m]*Q[m][k]; + for (int m=0; m<M; m++) u[m]-=ip*Q[m][k]; + R[k][n]=ip; + } + double iu=0; for (int m=0; m<M; m++) iu+=u[m]*u[m]; iu=sqrt(iu); + R[n][n]=iu; + iu=1.0/iu; for (int m=0; m<M; m++) Q[m][n]=u[m]*iu; + } + delete[] u; +}//QR_GS + +/* + function QR_householder: QR decomposition using householder transform + + In: A[M][N], M>=N + Out: Q[M][M], R[M][N] + + No return value. +*/ +void QR_householder(int M, int N, double** A, double** Q, double** R) +{ + double *u=new double[M*3], *ur=&u[M], *qu=&u[M*2]; + for (int m=0; m<M; m++) + { + memcpy(R[m], A[m], sizeof(double)*N); + memset(Q[m], 0, sizeof(double)*M); Q[m][m]=1; + } + for (int n=0; n<N; n++) + { + double alf=0; for (int m=n; m<M; m++) alf+=R[m][n]*R[m][n]; alf=sqrt(alf); + if (R[n][n]>0) alf=-alf; + for (int m=n; m<M; m++) u[m]=R[m][n]; u[n]=u[n]-alf; + double iu2=0; for (int m=n; m<M; m++) iu2+=u[m]*u[m]; iu2=2.0/iu2; + for (int m=n; m<N; m++) + { + ur[m]=0; for (int k=n; k<M; k++) ur[m]+=u[k]*R[k][m]; + } + for (int m=0; m<M; m++) + { + qu[m]=0; for (int k=n; k<M; k++) qu[m]+=Q[m][k]*u[k]; + } + for (int m=n; m<M; m++) u[m]=u[m]*iu2; + for (int m=n; m<M; m++) for (int k=n; k<N; k++) R[m][k]-=u[m]*ur[k]; + for (int m=0; m<M; m++) for (int k=n; k<M; k++) Q[m][k]-=qu[m]*u[k]; + } + delete[] u; +}//QR_householder + +//--------------------------------------------------------------------------- +/* + function QU: Unitary decomposition A=QU, where Q is unitary and U is upper triangular + + In: matrix A[N][N] + Out: matrices Q[N][N], A[n][n] now containing U + + No return value. +*/ +void QU(int N, double** Q, double** A) +{ + int sizeN=sizeof(double)*N; + for (int i=0; i<N; i++) {memset(Q[i], 0, sizeN); Q[i][i]=1;} + + double m, s, c, *tmpi=new double[N], *tmpj=new double[N]; + for (int i=1; i<N; i++) for (int j=0; j<i; j++) + if (A[i][j]!=0) + { + m=sqrt(A[j][j]*A[j][j]+A[i][j]*A[i][j]); + s=A[i][j]/m; + c=A[j][j]/m; + for (int k=0; k<N; k++) tmpi[k]=-s*A[j][k]+c*A[i][k], tmpj[k]=c*A[j][k]+s*A[i][k]; + memcpy(A[i], tmpi, sizeN), memcpy(A[j], tmpj, sizeN); + for (int k=0; k<N; k++) tmpi[k]=-s*Q[j][k]+c*Q[i][k], tmpj[k]=c*Q[j][k]+s*Q[i][k]; + memcpy(Q[i], tmpi, sizeN), memcpy(Q[j], tmpj, sizeN); + } + delete[] tmpi; delete[] tmpj; + transpose(N, Q); +}//QU + +//--------------------------------------------------------------------------- +/* + function Real: extracts the real part of matrix X + + In: matrix x[M][N]; + Out: matrix z[M][N] + + Returns pointer to z. z is created anew if z=0 is specified on start. +*/ +double** Real(int M, int N, double** z, cdouble** x, MList* List) +{ + if (!z){Allocate2(double, M, N, z); if (List) List->Add(z, 2);} + for (int m=0; m<M; m++) for (int n=0; n<N; n++) z[m][n]=x[m][n].x; + return z; +}//Real +double** Real(int M, int N, cdouble** x, MList* List){return Real(M, N, 0, x, List);} + +//--------------------------------------------------------------------------- +/* + function Roots: finds the roots of a polynomial. x^N+p[N-1]x^(N-1)+p[N-2]x^(N-2)...+p[0] + + In: vector p[N] of polynomial coefficients. + Out: vector r[N] of roots. + + Returns 0 if successful. +*/ +int Roots(int N, double* p, cdouble* r) +{ + double** A=new double*[N]; A[0]=new double[N*N]; for (int i=1; i<N; i++) A[i]=&A[0][i*N]; + for (int i=0; i<N; i++) A[0][i]=-p[N-1-i]; + if (N>1) memset(A[1], 0, sizeof(double)*N*(N-1)); + for (int i=1; i<N; i++) A[i][i-1]=1; + BalanceSim(N, A); + double result=QR(N, A, r); + delete[] A[0]; delete[] A; + return result; +}//Roots +//real implementation +int Roots(int N, double* p, double* rr, double* ri) +{ + cdouble* r=new cdouble[N]; + int result=Roots(N, p, r); + for (int n=0; n<N; n++) rr[n]=r[n].x, ri[n]=r[n].y; + delete[] r; + return result; +}//Roots + +//--------------------------------------------------------------------------- +/* + function SorI: Sor iteration algorithm for solving linear system Ax=b. + + Sor method is an extension of the Gaussian-Siedel method, with the latter equivalent to the former + with w set to 1. The Sor iteration is given by x(k)=(D-wL)^(-1)(((1-w)D+wU)x(k-1)+wb), where 0<w<2, D + is diagonal, L is lower triangular, U is upper triangular and A=L+D+U. Sor method converges if A is + positive definite. + + In: matrix A[N][N], vector b[N], initial vector x0[N] + Out: vector x0[N] + + Returns 0 if successful. Contents of matrix A and vector b are unchanged on return. +*/ +int SorI(int N, double* x0, double** a, double* b, double w, double ep, int maxiter) +{ + double e, v=1-w, *x=new double[N]; + int k=0, sizeN=sizeof(double)*N; + while (k<maxiter) + { + for (int i=0; i<N; i++) + { + x[i]=b[i]; + for (int j=0; j<i; j++) x[i]-=a[i][j]*x[j]; + for (int j=i+1; j<N; j++) x[i]-=a[i][j]*x0[j]; + x[i]=v*x0[i]+w*x[i]/a[i][i]; + } + e=0; for (int j=0; j<N; j++) e+=fabs(x[j]-x0[j]); + memcpy(x0, x, sizeN); + if (e<ep) break; + k++; + } + delete[] x; + if (k>=maxiter) return 1; + return 0; +}//SorI + +//--------------------------------------------------------------------------- +//Submatrix routines + +/* + function SetSubMatrix: copy matrix x[Y][X] into matrix z at (Y1, X1). + + In: matrix x[Y][X], matrix z with dimensions no less than [Y+Y1][X+X1] + Out: matrix z, updated. + + No return value. +*/ +void SetSubMatrix(double** z, double** x, int Y1, int Y, int X1, int X) +{ + for (int y=0; y<Y; y++) memcpy(&z[Y1+y][X1], x[y], sizeof(double)*X); +}//SetSubMatrix +//complex version +void SetSubMatrix(cdouble** z, cdouble** x, int Y1, int Y, int X1, int X) +{ + for (int y=0; y<Y; y++) memcpy(&z[Y1+y][X1], x[y], sizeof(cdouble)*X); +}//SetSubMatrix + +/* + function SubMatrix: extract a submatrix of x at (Y1, X1) to z[Y][X]. + + In: matrix x of dimensions no less than [Y+Y1][X+X1] + Out: matrix z[Y][X]. + + Returns pointer to z. z is created anew if z=0 is specifid on start. +*/ +cdouble** SubMatrix(cdouble** z, cdouble** x, int Y1, int Y, int X1, int X, MList* List) +{ + if (!z) {Allocate2(cdouble, Y, X, z); if (List) List->Add(z, 2);} + for (int y=0; y<Y; y++) memcpy(z[y], &x[Y1+y][X1], sizeof(cdouble)*X); + return z; +}//SetSubMatrix +//wrapper function +cdouble** SubMatrix(cdouble** x, int Y1, int Y, int X1, int X, MList* List) +{ + return SubMatrix(0, x, Y1, Y, X1, X, List); +}//SetSubMatrix + +/* + function SubVector: extract a subvector of x at X1 to z[X]. + + In: vector x no shorter than X+X1. + Out: vector z[X]. + + Returns pointer to z. z is created anew if z=0 is specifid on start. +*/ +cdouble* SubVector(cdouble* z, cdouble* x, int X1, int X, MList* List) +{ + if (!z){z=new cdouble[X]; if (List) List->Add(z, 1);} + memcpy(z, &x[X1], sizeof(cdouble)*X); + return z; +}//SubVector +//wrapper function +cdouble* SubVector(cdouble* x, int X1, int X, MList* List) +{ + return SubVector(0, x, X1, X, List); +}//SubVector + +//--------------------------------------------------------------------------- +/* + function transpose: matrix transpose: A'->A + + In: matrix a[N][N] + Out: matrix a[N][N] after transpose + + No return value. +*/ +void transpose(int N, double** a) +{ + double tmp; + for (int i=1; i<N; i++) for (int j=0; j<i; j++) {tmp=a[i][j]; a[i][j]=a[j][i]; a[j][i]=tmp;} +}//transpose +//complex version +void transpose(int N, cdouble** a) +{ + cdouble tmp; + for (int i=1; i<N; i++) for (int j=0; j<i; j++) {tmp=a[i][j]; a[i][j]=a[j][i]; a[j][i]=tmp;} +}//transpose + +/* + function transpose: matrix transpose: A'->Z + + In: matrix a[M][N] + Out: matrix z[N][M] + + Returns pointer to z. z is created anew if z=0 is specifid on start. +*/ +double** transpose(int N, int M, double** ta, double** a, MList* List) +{ + if (!ta) {Allocate2(double, N, M, ta); if (List) List->Add(ta, 2);} + for (int n=0; n<N; n++) for (int m=0; m<M; m++) ta[n][m]=a[m][n]; + return ta; +}//transpose +//wrapper function +double** transpose(int N, int M, double** a, MList* List) +{ + return transpose(N, M, 0, a, List); +}//transpose + +//--------------------------------------------------------------------------- +/* + function Unitary: given x & y s.t. |x|=|y|, find unitary matrix P s.t. Px=y. P is given in closed form + as I-(x-y)(x-y)'/(x-y)'x + + In: vectors x[N] and y[N] + Out: matrix P[N][N] + + Returns pointer to P. P is created anew if P=0 is specified on start. +*/ +double** Unitary(int N, double** P, double* x, double* y, MList* List) +{ + if (!P) {Allocate2(double, N, N, P); if (List) List->Add(P, 2);} + int sizeN=sizeof(double)*N; + for (int i=0; i<N; i++) {memset(P[i], 0, sizeN); P[i][i]=1;} + + double* w=MultiAdd(N, x, y, -1.0); //w=x-y + double m=Inner(N, x, w); //m=(x-y)'x + if (m!=0) + { + m=1.0/m; //m=1/(x-y)'x + double* mw=Multiply(N, w, m); + for (int i=0; i<N; i++) for (int j=0; j<N; j++) P[i][j]=P[i][j]-mw[i]*w[j]; + delete[] mw; + } + delete[] w; + return P; +}//Unitary +//complex version +cdouble** Unitary(int N, cdouble** P, cdouble* x, cdouble* y, MList* List) +{ + if (!P) {Allocate2(cdouble, N, N, P);} + int sizeN=sizeof(cdouble)*N; + for (int i=0; i<N; i++) {memset(P[i], 0, sizeN); P[i][i]=1;} + + cdouble *w=MultiAdd(N, x, y, -1); + cdouble m=Inner(N, x, w); + if (m!=0) + { + m=m.cinv(); + cdouble *mw=Multiply(N, w, m); + for (int i=0; i<N; i++) for (int j=0; j<N; j++) P[i][j]=P[i][j]-(mw[i]^w[j]), + delete[] mw; + } + delete[] w; + if (List) List->Add(P, 2); + return P; +}//Unitary +//wrapper functions +double** Unitary(int N, double* x, double* y, MList* List){return Unitary(N, 0, x, y, List);} +cdouble** Unitary(int N, cdouble* x, cdouble* y, MList* List){return Unitary(N, 0, x, y, List);} + + +