annotate 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
rev   line source
xue@1 1 //---------------------------------------------------------------------------
xue@1 2 #include <math.h>
xue@1 3 #include <memory.h>
Chris@2 4 #include "matrix.h"
xue@1 5 //---------------------------------------------------------------------------
xue@1 6 /*
xue@1 7 function BalanceSim: applies a similarity transformation to matrix a so that a is "balanced". This is
xue@1 8 used by various eigenvalue evaluation routines.
xue@1 9
xue@1 10 In: matrix A[n][n]
xue@1 11 Out: balanced matrix a
xue@1 12
xue@1 13 No return value.
xue@1 14 */
xue@1 15 void BalanceSim(int n, double** A)
xue@1 16 {
xue@1 17 if (n<2) return;
xue@1 18 const int radix=2;
xue@1 19 double sqrdx;
xue@1 20 sqrdx=radix*radix;
xue@1 21 bool finish=false;
xue@1 22 while (!finish)
xue@1 23 {
xue@1 24 finish=true;
xue@1 25 for (int i=0; i<n; i++)
xue@1 26 {
xue@1 27 double s, sr=0, sc=0, ar, ac;
xue@1 28 for (int j=0; j<n; j++)
xue@1 29 if (j!=i)
xue@1 30 {
xue@1 31 sc+=fabs(A[j][i]);
xue@1 32 sr+=fabs(A[i][j]);
xue@1 33 }
xue@1 34 if (sc!=0 && sr!=0)
xue@1 35 {
xue@1 36 ar=sr/radix;
xue@1 37 ac=1.0;
xue@1 38 s=sr+sc;
xue@1 39 while (sc<ar)
xue@1 40 {
xue@1 41 ac*=radix;
xue@1 42 sc*=sqrdx;
xue@1 43 }
xue@1 44 ar=sr*radix;
xue@1 45 while (sc>ar)
xue@1 46 {
xue@1 47 ac/=radix;
xue@1 48 sc/=sqrdx;
xue@1 49 }
xue@1 50 }
xue@1 51 if ((sc+sr)/ac<0.95*s)
xue@1 52 {
xue@1 53 finish=false;
xue@1 54 ar=1.0/ac;
xue@1 55 for (int j=0; j<n; j++) A[i][j]*=ar;
xue@1 56 for (int j=0; j<n; j++) A[j][i]*=ac;
xue@1 57 }
xue@1 58 }
xue@1 59 }
xue@1 60 }//BalanceSim
xue@1 61
xue@1 62 //---------------------------------------------------------------------------
xue@1 63 /*
xue@1 64 function Choleski: Choleski factorization A=LL', where L is lower triangular. The symmetric matrix
xue@1 65 A[N][N] is positive definite iff A can be factored as LL', where L is lower triangular with nonzero
xue@1 66 diagonl entries.
xue@1 67
xue@1 68 In: matrix A[N][N]
xue@1 69 Out: mstrix L[N][N].
xue@1 70
xue@1 71 Returns 0 if successful. On return content of matrix a is not changed.
xue@1 72 */
xue@1 73 int Choleski(int N, double** L, double** A)
xue@1 74 {
xue@1 75 if (A[0][0]==0) return 1;
xue@1 76 L[0][0]=sqrt(A[0][0]);
xue@1 77 memset(&L[0][1], 0, sizeof(double)*(N-1));
xue@1 78 for (int j=1; j<N; j++) L[j][0]=A[j][0]/L[0][0];
xue@1 79 for (int i=1; i<N-1; i++)
xue@1 80 {
xue@1 81 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]);
xue@1 82 if (L[i][i]==0) return 1;
xue@1 83 for (int j=i+1; j<N; j++)
xue@1 84 {
xue@1 85 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];
xue@1 86 }
xue@1 87 memset(&L[i][i+1], 0, sizeof(double)*(N-1-i));
xue@1 88 }
xue@1 89 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]);
xue@1 90 return 0;
xue@1 91 }//Choleski
xue@1 92
xue@1 93 //---------------------------------------------------------------------------
xue@1 94 //matrix duplication routines
xue@1 95
xue@1 96 /*
xue@1 97 function Copy: duplicate the matrix A as matrix Z.
xue@1 98
xue@1 99 In: matrix A[M][N]
xue@1 100 Out: matrix Z[M][N]
xue@1 101
xue@1 102 Returns pointer to Z. Z is created anew if Z=0 is supplied on start.
xue@1 103 */
xue@1 104 double** Copy(int M, int N, double** Z, double** A, MList* List)
xue@1 105 {
xue@1 106 if (!Z) {Allocate2(double, M, N, Z); if (List) List->Add(Z, 2);}
xue@1 107 int sizeN=sizeof(double)*N;
xue@1 108 for (int m=0; m<M; m++) memcpy(Z[m], A[m], sizeN);
xue@1 109 return Z;
xue@1 110 }//Copy
xue@1 111 //complex version
xue@1 112 cdouble** Copy(int M, int N, cdouble** Z, cdouble** A, MList* List)
xue@1 113 {
xue@1 114 if (!Z) {Allocate2(cdouble, M, N, Z); if (List) List->Add(Z, 2);}
xue@1 115 int sizeN=sizeof(cdouble)*N;
xue@1 116 for (int m=0; m<M; m++) memcpy(Z[m], A[m], sizeN);
xue@1 117 return Z;
xue@1 118 }//Copy
xue@1 119 //version without specifying pre-allocated z
xue@1 120 double** Copy(int M, int N, double** A, MList* List){return Copy(M, N, 0, A, List);}
xue@1 121 cdouble** Copy(int M, int N, cdouble** A, MList* List){return Copy(M, N, 0, A, List);}
xue@1 122 //for square matrices
xue@1 123 double** Copy(int N, double** Z, double ** A, MList* List){return Copy(N, N, Z, A, List);}
xue@1 124 double** Copy(int N, double** A, MList* List){return Copy(N, N, 0, A, List);}
xue@1 125 cdouble** Copy(int N, cdouble** Z, cdouble** A, MList* List){return Copy(N, N, Z, A, List);}
xue@1 126 cdouble** Copy(int N, cdouble** A, MList* List){return Copy(N, N, 0, A, List);}
xue@1 127
xue@1 128 //---------------------------------------------------------------------------
xue@1 129 //vector duplication routines
xue@1 130
xue@1 131 /*
xue@1 132 function Copy: duplicating vector a as vector z
xue@1 133
xue@1 134 In: vector a[N]
xue@1 135 Out: vector z[N]
xue@1 136
xue@1 137 Returns pointer to z. z is created anew is z=0 is specified on start.
xue@1 138 */
xue@1 139 double* Copy(int N, double* z, double* a, MList* List)
xue@1 140 {
xue@1 141 if (!z){z=new double[N]; if (List) List->Add(z, 1);}
xue@1 142 memcpy(z, a, sizeof(double)*N);
xue@1 143 return z;
xue@1 144 }//Copy
xue@1 145 cdouble* Copy(int N, cdouble* z, cdouble* a, MList* List)
xue@1 146 {
xue@1 147 if (!z){z=new cdouble[N]; if (List) List->Add(z, 1);}
xue@1 148 memcpy(z, a, sizeof(cdouble)*N);
xue@1 149 return z;
xue@1 150 }//Copy
xue@1 151 //version without specifying pre-allocated z
xue@1 152 double* Copy(int N, double* a, MList* List){return Copy(N, 0, a, List);}
xue@1 153 cdouble* Copy(int N, cdouble* a, MList* List){return Copy(N, 0, a, List);}
xue@1 154
xue@1 155 //---------------------------------------------------------------------------
xue@1 156 /*
xue@1 157 function det: computes determinant by Gaussian elimination method with column pivoting
xue@1 158
xue@1 159 In: matrix A[N][N]
xue@1 160
xue@1 161 Returns det(A). On return content of matrix A is unchanged if mode=0.
xue@1 162 */
xue@1 163 double det(int N, double** A, int mode)
xue@1 164 {
xue@1 165 int c, p, ip, *rp=new int[N]; for (int i=0; i<N; i++) rp[i]=i;
xue@1 166 double m, **b, result=1;
xue@1 167
xue@1 168 if (mode==0)
xue@1 169 {
xue@1 170 int sizeN=sizeof(double)*N;
xue@1 171 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);}
xue@1 172 A=b;
xue@1 173 }
xue@1 174
xue@1 175 //Gaussian eliminating
xue@1 176 for (int i=0; i<N-1; i++)
xue@1 177 {
xue@1 178 p=i, ip=i+1;
xue@1 179 while (ip<N){if (fabs(A[rp[ip]][i])>fabs(A[rp[p]][i])) p=ip; ip++;}
xue@1 180 if (A[rp[p]][i]==0) {result=0; goto ret;}
xue@1 181 if (p!=i) {c=rp[i]; rp[i]=rp[p]; rp[p]=c; result=-result;}
xue@1 182 for (int j=i+1; j<N; j++)
xue@1 183 {
xue@1 184 m=A[rp[j]][i]/A[rp[i]][i];
xue@1 185 A[rp[j]][i]=0;
xue@1 186 for (int k=i+1; k<N; k++) A[rp[j]][k]-=m*A[rp[i]][k];
xue@1 187 }
xue@1 188 }
xue@1 189 if (A[rp[N-1]][N-1]==0) {result=0; goto ret;}
xue@1 190
xue@1 191 for (int i=0; i<N; i++)
xue@1 192 result*=A[rp[i]][i];
xue@1 193
xue@1 194 ret:
xue@1 195 if (mode==0) {delete[] b[0]; delete[] b;}
xue@1 196 delete[] rp;
xue@1 197 return result;
xue@1 198 }//det
xue@1 199 //complex version
xue@1 200 cdouble det(int N, cdouble** A, int mode)
xue@1 201 {
xue@1 202 int c, p, ip, *rp=new int[N]; for (int i=0; i<N; i++) rp[i]=i;
xue@1 203 double mm, mp;
xue@1 204 cdouble m, **b, result=1;
xue@1 205
xue@1 206 if (mode==0)
xue@1 207 {
xue@1 208 int sizeN=sizeof(cdouble)*N;
xue@1 209 b=new cdouble*[N]; b[0]=new cdouble[N*N];
xue@1 210 for (int i=0; i<N; i++) {b[i]=&b[0][i*N]; memcpy(b[i], A[i], sizeN);}
xue@1 211 A=b;
xue@1 212 }
xue@1 213
xue@1 214 //Gaussian elimination
xue@1 215 for (int i=0; i<N-1; i++)
xue@1 216 {
xue@1 217 p=i, ip=i+1; m=A[rp[p]][i]; mp=~m;
xue@1 218 while (ip<N){m=A[rp[ip]][i]; mm=~m; if (mm>mp) mp=mm, p=ip; ip++;}
xue@1 219 if (mp==0) {result=0; goto ret;}
xue@1 220 if (p!=i) {c=rp[i]; rp[i]=rp[p]; rp[p]=c;}
xue@1 221 for (int j=i+1; j<N; j++)
xue@1 222 {
xue@1 223 m=A[rp[j]][i]/A[rp[i]][i];
xue@1 224 A[rp[j]][i]=0;
xue@1 225 for (int k=i+1; k<N; k++) A[rp[j]][k]-=m*A[rp[i]][k];
xue@1 226 }
xue@1 227 }
xue@1 228 if (operator==(A[rp[N-1]][N-1],0)) {result=0; goto ret;}
xue@1 229
xue@1 230 for (int i=0; i<N; i++) result=result*A[rp[i]][i];
xue@1 231 ret:
xue@1 232 if (mode==0) {delete[] b[0]; delete[] b;}
xue@1 233 delete[] rp;
xue@1 234 return result;
xue@1 235 }//det
xue@1 236
xue@1 237 //---------------------------------------------------------------------------
xue@1 238 /*
xue@1 239 function EigPower: power method for solving dominant eigenvalue and eigenvector
xue@1 240
xue@1 241 In: matrix A[N][N], initial arbitrary vector x[N].
xue@1 242 Out: eigenvalue l, eigenvector x[N].
xue@1 243
xue@1 244 Returns 0 is successful. Content of matrix A is unchangd on return. Initial x[N] must not be zero.
xue@1 245 */
xue@1 246 int EigPower(int N, double& l, double* x, double** A, double ep, int maxiter)
xue@1 247 {
xue@1 248 int k=0;
xue@1 249 int p=0; for (int i=1; i<N; i++) if (fabs(x[p])<fabs(x[i])) p=i;
xue@1 250 Multiply(N, x, x, 1/x[p]);
xue@1 251 double e, ty,te, *y=new double[N];
xue@1 252
xue@1 253 while (k<maxiter)
xue@1 254 {
xue@1 255 MultiplyXy(N, N, y, A, x);
xue@1 256 l=y[p];
xue@1 257 int p=0; for (int i=1; i<N; i++) if (fabs(y[p])<fabs(y[i])) p=i;
xue@1 258 if (y[p]==0) {l=0; delete[] y; return 0;}
xue@1 259 ty=y[0]/y[p]; e=fabs(x[0]-ty); x[0]=ty;
xue@1 260 for (int i=1; i<N; i++)
xue@1 261 {
xue@1 262 ty=y[i]/y[p]; te=fabs(x[i]-ty); if (e<te) e=te; x[i]=ty;
xue@1 263 }
xue@1 264 if (e<ep) {delete[] y; return 0;}
xue@1 265 k++;
xue@1 266 }
xue@1 267 delete[] y; return 1;
xue@1 268 }//EigPower
xue@1 269
xue@1 270 //---------------------------------------------------------------------------
xue@1 271 /*
xue@1 272 function EigPowerA: EigPower with Aitken acceleration
xue@1 273
xue@1 274 In: matrix A[N][N], initial arbitrary vector x[N].
xue@1 275 Out: eigenvalue l, eigenvector x[N].
xue@1 276
xue@1 277 Returns 0 is successful. Content of matrix A is unchangd on return. Initial x[N] must not be zero.
xue@1 278 */
xue@1 279 int EigPowerA(int N, double& l, double* x, double** A, double ep, int maxiter)
xue@1 280 {
xue@1 281 int k=0;
xue@1 282 int p=0; for (int i=1; i<N; i++) if (fabs(x[p])<fabs(x[i])) p=i;
xue@1 283 Multiply(N, x, x, 1/x[p]);
xue@1 284 double m, m0=0, m1=0, e, ty,te, *y=new double[N];
xue@1 285
xue@1 286 while (k<maxiter)
xue@1 287 {
xue@1 288 MultiplyXy(N, N, y, A, x);
xue@1 289 m=y[p];
xue@1 290 int p=0; for (int i=1; i<N; i++) if (fabs(y[p])<fabs(y[i])) p=i;
xue@1 291 if (y[p]==0) {l=0; delete[] y; return 0;}
xue@1 292 ty=y[0]/y[p]; e=fabs(x[0]-ty); x[0]=ty;
xue@1 293 for (int i=1; i<N; i++)
xue@1 294 {
xue@1 295 ty=y[i]/y[p]; te=fabs(x[i]-ty); if (e<te) e=te; x[i]=ty;
xue@1 296 }
xue@1 297 if (e<ep && k>2) {l=m0-(m1-m0)*(m1-m0)/(m-2*m1+m0); delete[] y; return 0;}
xue@1 298 k++; m0=m1; m1=m;
xue@1 299 }
xue@1 300 delete[] y; return 1;
xue@1 301 }//EigPowerA
xue@1 302
xue@1 303 //---------------------------------------------------------------------------
xue@1 304 /*
xue@1 305 function EigPowerI: Inverse power method for solving the eigenvalue given an approximate non-zero
xue@1 306 eigenvector.
xue@1 307
xue@1 308 In: matrix A[N][N], approximate eigenvector x[N].
xue@1 309 Out: eigenvalue l, eigenvector x[N].
xue@1 310
xue@1 311 Returns 0 is successful. Content of matrix A is unchangd on return. Initial x[N] must not be zero.
xue@1 312 */
xue@1 313 int EigPowerI(int N, double& l, double* x, double** A, double ep, int maxiter)
xue@1 314 {
xue@1 315 int sizeN=sizeof(double)*N;
xue@1 316 double* y=new double[N]; MultiplyXy(N, N, y, A, x);
xue@1 317 double q=Inner(N, x, y)/Inner(N, x, x), dt;
xue@1 318 double** aa=new double*[N]; aa[0]=new double[N*N];
xue@1 319 for (int i=0; i<N; i++) {aa[i]=&aa[0][i*N]; memcpy(aa[i], A[i], sizeN); aa[i][i]-=q;}
xue@1 320 dt=GISCP(N, aa);
xue@1 321 if (dt==0) {l=q; delete[] aa[0]; delete[] aa; delete[] y; return 0;}
xue@1 322
xue@1 323 int k=0;
xue@1 324 int p=0; for (int i=1; i<N; i++) if (fabs(x[p])<fabs(x[i])) p=i;
xue@1 325 Multiply(N, x, x, 1/x[p]);
xue@1 326
xue@1 327 double m, e, ty, te;
xue@1 328 while (k<N)
xue@1 329 {
xue@1 330 MultiplyXy(N, N, y, aa, x);
xue@1 331 m=y[p];
xue@1 332 p=0; for (int i=1; i<N; i++) if (fabs(y[p])<fabs(y[i])) p=i;
xue@1 333 ty=y[0]/y[p]; te=x[0]-ty; e=fabs(te); x[0]=ty;
xue@1 334 for (int i=1; i<N; i++)
xue@1 335 {
xue@1 336 ty=y[i]/y[p]; te=fabs(x[i]-ty); if (e<te) e=te; x[i]=ty;
xue@1 337 }
xue@1 338 if (e<ep) {l=1/m+q; delete[] aa[0]; delete[] aa; delete[] y; return 0;}
xue@1 339 }
xue@1 340 delete[] aa[0]; delete[] aa;
xue@1 341 delete[] y; return 1;
xue@1 342 }//EigPowerI
xue@1 343
xue@1 344 //---------------------------------------------------------------------------
xue@1 345 /*
xue@1 346 function EigPowerS: symmetric power method for solving the dominant eigenvalue with its eigenvector
xue@1 347
xue@1 348 In: matrix A[N][N], initial arbitrary vector x[N].
xue@1 349 Out: eigenvalue l, eigenvector x[N].
xue@1 350
xue@1 351 Returns 0 is successful. Content of matrix A is unchangd on return. Initial x[N] must not be zero.
xue@1 352 */
xue@1 353 int EigPowerS(int N, double& l, double* x, double** A, double ep, int maxiter)
xue@1 354 {
xue@1 355 int k=0;
xue@1 356 Multiply(N, x, x, 1/sqrt(Inner(N, x, x)));
xue@1 357 double y2, e, ty, te, *y=new double[N];
xue@1 358 while (k<maxiter)
xue@1 359 {
xue@1 360 MultiplyXy(N, N, y, A, x);
xue@1 361 l=Inner(N, x, y);
xue@1 362 y2=sqrt(Inner(N, y, y));
xue@1 363 if (y2==0) {l=0; delete[] y; return 0;}
xue@1 364 ty=y[0]/y2; te=x[0]-ty; e=te*te; x[0]=ty;
xue@1 365 for (int i=1; i<N; i++)
xue@1 366 {
xue@1 367 ty=y[i]/y2; te=x[i]-ty; e+=te*te; x[i]=ty;
xue@1 368 }
xue@1 369 e=sqrt(e);
xue@1 370 if (e<ep) {delete[] y; return 0;}
xue@1 371 k++;
xue@1 372 }
xue@1 373 delete[] y;
xue@1 374 return 1;
xue@1 375 }//EigPowerS
xue@1 376
xue@1 377 //---------------------------------------------------------------------------
xue@1 378 /*
xue@1 379 function EigPowerWielandt: Wielandt's deflation algorithm for solving a second dominant eigenvalue and
xue@1 380 eigenvector (m,u) given the dominant eigenvalue and eigenvector (l,v).
xue@1 381
xue@1 382 In: matrix A[N][N], first eigenvalue l with eigenvector v[N]
xue@1 383 Out: second eigenvalue m with eigenvector u
xue@1 384
xue@1 385 Returns 0 if successful. Content of matrix A is unchangd on return. Initial u[N] must not be zero.
xue@1 386 */
xue@1 387 int EigPowerWielandt(int N, double& m, double* u, double l, double* v, double** A, double ep, int maxiter)
xue@1 388 {
xue@1 389 int result;
xue@1 390 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)];
xue@1 391 double* w=new double[N];
xue@1 392 int i=0; for (int j=1; j<N; j++) if (fabs(v[i])<fabs(v[j])) i=j;
xue@1 393 if (i!=0)
xue@1 394 for (int k=0; k<i; k++)
xue@1 395 for (int j=0; j<i; j++)
xue@1 396 b[k][j]=A[k][j]-v[k]*A[i][j]/v[i];
xue@1 397 if (i!=0 && i!=N-1)
xue@1 398 for (int k=i; k<N-1; k++)
xue@1 399 for (int j=0; j<i; j++)
xue@1 400 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];
xue@1 401 if (i!=N-1)
xue@1 402 for (int k=i; k<N-1; k++)
xue@1 403 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];
xue@1 404 memcpy(w, u, sizeof(double)*(N-1));
xue@1 405 if ((result=EigPower(N-1, m, w, b, ep, maxiter))==0)
xue@1 406 { //*
xue@1 407 if (i!=N-1) memmove(&w[i+1], &w[i], sizeof(double)*(N-i-1));
xue@1 408 w[i]=0;
xue@1 409 for (int k=0; k<N; k++) u[k]=(m-l)*w[k]+Inner(N, A[i], w)*v[k]/v[i]; //*/
xue@1 410 }
xue@1 411 delete[] w; delete[] b[0]; delete[] b;
xue@1 412 return result;
xue@1 413 }//EigPowerWielandt
xue@1 414
xue@1 415 //---------------------------------------------------------------------------
xue@1 416 //NR versions of eigensystem
xue@1 417
xue@1 418 /*
xue@1 419 function EigenValues: solves for eigenvalues of general system
xue@1 420
xue@1 421 In: matrix A[N][N]
xue@1 422 Out: eigenvalues ev[N]
xue@1 423
xue@1 424 Returns 0 if successful. Content of matrix A is destroyed on return.
xue@1 425 */
xue@1 426 int EigenValues(int N, double** A, cdouble* ev)
xue@1 427 {
xue@1 428 BalanceSim(N, A);
xue@1 429 Hessenb(N, A);
xue@1 430 return QR(N, A, ev);
xue@1 431 }//EigenValues
xue@1 432
xue@1 433 /*
xue@1 434 function EigSym: Solves real symmetric eigensystem A
xue@1 435
xue@1 436 In: matrix A[N][N]
xue@1 437 Out: eigenvalues d[N], transform matrix Q[N][N], so that diag(d)=Q'AQ, A=Q diag(d) Q', AQ=Q diag(d)
xue@1 438
xue@1 439 Returns 0 if successful. Content of matrix A is unchanged on return.
xue@1 440 */
xue@1 441 int EigSym(int N, double** A, double* d, double** Q)
xue@1 442 {
xue@1 443 Copy(N, Q, A);
xue@1 444 double* t=new double[N];
xue@1 445 HouseHolder(5, Q, d, t);
xue@1 446 double result=QL(5, d, t, Q);
xue@1 447 delete[] t;
xue@1 448 return result;
xue@1 449 }//EigSym
xue@1 450
xue@1 451 //---------------------------------------------------------------------------
xue@1 452 /*
xue@1 453 function GEB: Gaussian elimination with backward substitution for solving linear system Ax=b.
xue@1 454
xue@1 455 In: coefficient matrix A[N][N], vector b[N]
xue@1 456 Out: vector x[N]
xue@1 457
xue@1 458 Returns 0 if successful. Contents of matrix A and vector b are destroyed on return.
xue@1 459 */
xue@1 460 int GEB(int N, double* x, double** A, double* b)
xue@1 461 {
xue@1 462 //Gaussian eliminating
xue@1 463 int c, p, *rp=new int[N]; for (int i=0; i<N; i++) rp[i]=i;
xue@1 464 double m;
xue@1 465 for (int i=0; i<N-1; i++)
xue@1 466 {
xue@1 467 p=i;
xue@1 468 while (p<N && A[rp[p]][i]==0) p++;
xue@1 469 if (p>=N) {delete[] rp; return 1;}
xue@1 470 if (p!=i){c=rp[i]; rp[i]=rp[p]; rp[p]=c;}
xue@1 471 for (int j=i+1; j<N; j++)
xue@1 472 {
xue@1 473 m=A[rp[j]][i]/A[rp[i]][i];
xue@1 474 A[rp[j]][i]=0;
xue@1 475 for (int k=i+1; k<N; k++) A[rp[j]][k]-=m*A[rp[i]][k];
xue@1 476 b[rp[j]]-=m*b[rp[i]];
xue@1 477 }
xue@1 478 }
xue@1 479 if (A[rp[N-1]][N-1]==0) {delete[] rp; return 1;}
xue@1 480 else
xue@1 481 {
xue@1 482 //backward substitution
xue@1 483 x[N-1]=b[rp[N-1]]/A[rp[N-1]][N-1];
xue@1 484 for (int i=N-2; i>=0; i--)
xue@1 485 {
xue@1 486 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];
xue@1 487 }
xue@1 488 }
xue@1 489 delete[] rp;
xue@1 490 return 0;
xue@1 491 }//GEB
xue@1 492
xue@1 493 //---------------------------------------------------------------------------
xue@1 494 /*
xue@1 495 function GESCP: Gaussian elimination with scaled column pivoting for solving linear system Ax=b
xue@1 496
xue@1 497 In: matrix A[N][N], vector b[N]
xue@1 498 Out: vector x[N]
xue@1 499
xue@1 500 Returns 0 is successful. Contents of matrix A and vector b are destroyed on return.
xue@1 501 */
xue@1 502 int GESCP(int N, double* x, double** A, double *b)
xue@1 503 {
xue@1 504 int c, p, ip, *rp=new int[N];
xue@1 505 double m, *s=new double[N];
xue@1 506 for (int i=0; i<N; i++)
xue@1 507 {
xue@1 508 s[i]=fabs(A[i][0]);
xue@1 509 for (int j=1; j<N; j++) if (s[i]<fabs(A[i][j])) s[i]=fabs(A[i][j]);
xue@1 510 if (s[i]==0) {delete[] s; delete[] rp; return 1;}
xue@1 511 rp[i]=i;
xue@1 512 }
xue@1 513 //Gaussian eliminating
xue@1 514 for (int i=0; i<N-1; i++)
xue@1 515 {
xue@1 516 p=i, ip=i+1;
xue@1 517 while (ip<N){if (fabs(A[rp[ip]][i])/s[rp[ip]]>fabs(A[rp[p]][i])/s[rp[p]]) p=ip; ip++;}
xue@1 518 if (A[rp[p]][i]==0) {delete[] s; delete[] rp; return 1;}
xue@1 519 if (p!=i) {c=rp[i]; rp[i]=rp[p]; rp[p]=c;}
xue@1 520 for (int j=i+1; j<N; j++)
xue@1 521 {
xue@1 522 m=A[rp[j]][i]/A[rp[i]][i];
xue@1 523 A[rp[j]][i]=0;
xue@1 524 for (int k=i+1; k<N; k++) A[rp[j]][k]-=m*A[rp[i]][k];
xue@1 525 b[rp[j]]-=m*b[rp[i]];
xue@1 526 }
xue@1 527 }
xue@1 528 if (A[rp[N-1]][N-1]==0) {delete[] s; delete[] rp; return 1;}
xue@1 529 //backward substitution
xue@1 530 x[N-1]=b[rp[N-1]]/A[rp[N-1]][N-1];
xue@1 531 for (int i=N-2; i>=0; i--)
xue@1 532 {
xue@1 533 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];
xue@1 534 }
xue@1 535 delete[] s; delete[] rp;
xue@1 536 return 0;
xue@1 537 }//GESCP
xue@1 538
xue@1 539 //---------------------------------------------------------------------------
xue@1 540 /*
xue@1 541 function GExL: solves linear system xL=a, L being lower-triangular. This is used in LU factorization
xue@1 542 for solving linear systems.
xue@1 543
xue@1 544 In: lower-triangular matrix L[N][N], vector a[N]
xue@1 545 Out: vector x[N]
xue@1 546
xue@1 547 No return value. Contents of matrix L and vector a are unchanged at return.
xue@1 548 */
xue@1 549 void GExL(int N, double* x, double** L, double* a)
xue@1 550 {
xue@1 551 for (int n=N-1; n>=0; n--)
xue@1 552 {
xue@1 553 double xn=a[n];
xue@1 554 for (int m=n+1; m<N; m++) xn-=x[m]*L[m][n];
xue@1 555 x[n]=xn/L[n][n];
xue@1 556 }
xue@1 557 }//GExL
xue@1 558
xue@1 559 /*
xue@1 560 function GExLAdd: solves linear system *L=a, L being lower-triangular, and add the solution * to x[].
xue@1 561
xue@1 562 In: lower-triangular matrix L[N][N], vector a[N]
xue@1 563 Out: updated vector x[N]
xue@1 564
xue@1 565 No return value. Contents of matrix L and vector a are unchanged at return.
xue@1 566 */
xue@1 567 void GExLAdd(int N, double* x, double** L, double* a)
xue@1 568 {
xue@1 569 double* lx=new double[N];
xue@1 570 GExL(N, lx, L, a);
xue@1 571 for (int i=0; i<N; i++) x[i]+=lx[i];
xue@1 572 delete[] lx;
xue@1 573 }//GExLAdd
xue@1 574
xue@1 575 /*
xue@1 576 function GExL1: solves linear system xL=(0, 0, ..., 0, a)', L being lower-triangular.
xue@1 577
xue@1 578 In: lower-triangular matrix L[N][N], a
xue@1 579 Out: vector x[N]
xue@1 580
xue@1 581 No return value. Contents of matrix L and vector a are unchanged at return.
xue@1 582 */
xue@1 583 void GExL1(int N, double* x, double** L, double a)
xue@1 584 {
xue@1 585 double xn=a;
xue@1 586 for (int n=N-1; n>=0; n--)
xue@1 587 {
xue@1 588 for (int m=n+1; m<N; m++) xn-=x[m]*L[m][n];
xue@1 589 x[n]=xn/L[n][n];
xue@1 590 xn=0;
xue@1 591 }
xue@1 592 }//GExL1
xue@1 593
xue@1 594 /*
xue@1 595 function GExL1Add: solves linear system *L=(0, 0, ..., 0, a)', L being lower-triangular, and add the
xue@1 596 solution * to x[].
xue@1 597
xue@1 598 In: lower-triangular matrix L[N][N], vector a
xue@1 599 Out: updated vector x[N]
xue@1 600
xue@1 601 No return value. Contents of matrix L and vector a are unchanged at return.
xue@1 602 */
xue@1 603 void GExL1Add(int N, double* x, double** L, double a)
xue@1 604 {
xue@1 605 double* lx=new double[N];
xue@1 606 GExL1(N, lx, L, a);
xue@1 607 for (int i=0; i<N; i++) x[i]+=lx[i];
xue@1 608 delete[] lx;
xue@1 609 }//GExL1Add
xue@1 610
xue@1 611 //---------------------------------------------------------------------------
xue@1 612 /*
xue@1 613 function GICP: matrix inverse using Gaussian elimination with column pivoting: inv(A)->A.
xue@1 614
xue@1 615 In: matrix A[N][N]
xue@1 616 Out: matrix A[N][N]
xue@1 617
xue@1 618 Returns the determinant of the inverse matrix, 0 on failure.
xue@1 619 */
xue@1 620 double GICP(int N, double** A)
xue@1 621 {
xue@1 622 int c, p, ip, *rp=new int[N]; for (int i=0; i<N; i++) rp[i]=i;
xue@1 623 double m, result=1;
xue@1 624
xue@1 625 //Gaussian eliminating
xue@1 626 for (int i=0; i<N-1; i++)
xue@1 627 {
xue@1 628 p=i, ip=i+1;
xue@1 629 while (ip<N){if (fabs(A[rp[ip]][i])>fabs(A[rp[p]][i])) p=ip; ip++;}
xue@1 630 if (A[rp[p]][i]==0) {delete[] rp; return 0;}
xue@1 631 if (p!=i) {c=rp[i]; rp[i]=rp[p]; rp[p]=c; result=-result;}
xue@1 632 result/=A[rp[i]][i];
xue@1 633 for (int j=i+1; j<N; j++)
xue@1 634 {
xue@1 635 m=A[rp[j]][i]/A[rp[i]][i];
xue@1 636 A[rp[j]][i]=-m;
xue@1 637 for (int k=i+1; k<N; k++) A[rp[j]][k]-=m*A[rp[i]][k];
xue@1 638 for (int k=0; k<i; k++) A[rp[j]][k]-=m*A[rp[i]][k];
xue@1 639 }
xue@1 640 }
xue@1 641 if (A[rp[N-1]][N-1]==0) {delete[] rp; return 0;}
xue@1 642 result/=A[rp[N-1]][N-1];
xue@1 643 //backward substitution
xue@1 644 for (int i=0; i<N-1; i++)
xue@1 645 {
xue@1 646 m=A[rp[i]][i]; for (int k=0; k<N; k++) A[rp[i]][k]/=m; A[rp[i]][i]=1/m;
xue@1 647 for (int j=i+1; j<N; j++)
xue@1 648 {
xue@1 649 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;
xue@1 650 }
xue@1 651 }
xue@1 652 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;
xue@1 653 //recover column and row exchange
xue@1 654 double* tm=new double[N]; int sizeN=sizeof(double)*N;
xue@1 655 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); }
xue@1 656 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];}
xue@1 657
xue@1 658 delete[] tm; delete[] rp;
xue@1 659 return result;
xue@1 660 }//GICP
xue@1 661 //complex version
xue@1 662 cdouble GICP(int N, cdouble** A)
xue@1 663 {
xue@1 664 int c, p, ip, *rp=new int[N]; for (int i=0; i<N; i++) rp[i]=i;
xue@1 665 cdouble m, result=1;
xue@1 666
xue@1 667 //Gaussian eliminating
xue@1 668 for (int i=0; i<N-1; i++)
xue@1 669 {
xue@1 670 p=i, ip=i+1;
xue@1 671 while (ip<N){if (~A[rp[ip]][i]>~A[rp[p]][i]) p=ip; ip++;}
xue@1 672 if (A[rp[p]][i]==0) {delete[] rp; return 0;}
xue@1 673 if (p!=i) {c=rp[i]; rp[i]=rp[p]; rp[p]=c; result=-result;}
xue@1 674 result=result/(A[rp[i]][i]);
xue@1 675 for (int j=i+1; j<N; j++)
xue@1 676 {
xue@1 677 m=A[rp[j]][i]/A[rp[i]][i];
xue@1 678 A[rp[j]][i]=-m;
xue@1 679 for (int k=i+1; k<N; k++) A[rp[j]][k]-=m*A[rp[i]][k];
xue@1 680 for (int k=0; k<i; k++) A[rp[j]][k]-=m*A[rp[i]][k];
xue@1 681 }
xue@1 682 }
xue@1 683 if (A[rp[N-1]][N-1]==0) {delete[] rp; return 0;}
xue@1 684 result=result/A[rp[N-1]][N-1];
xue@1 685 //backward substitution
xue@1 686 for (int i=0; i<N-1; i++)
xue@1 687 {
xue@1 688 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;
xue@1 689 for (int j=i+1; j<N; j++)
xue@1 690 {
xue@1 691 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;
xue@1 692 }
xue@1 693 }
xue@1 694 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;
xue@1 695 //recover column and row exchange
xue@1 696 cdouble* tm=new cdouble[N]; int sizeN=sizeof(cdouble)*N;
xue@1 697 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); }
xue@1 698 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];}
xue@1 699
xue@1 700 delete[] tm; delete[] rp;
xue@1 701 return result;
xue@1 702 }//GICP
xue@1 703
xue@1 704 /*
xue@1 705 function GICP: wrapper function that does not overwrite the input matrix: inv(A)->X.
xue@1 706
xue@1 707 In: matrix A[N][N]
xue@1 708 Out: matrix X[N][N]
xue@1 709
xue@1 710 Returns the determinant of the inverse matrix, 0 on failure.
xue@1 711 */
xue@1 712 double GICP(int N, double** X, double** A)
xue@1 713 {
xue@1 714 Copy(N, X, A);
xue@1 715 return GICP(N, X);
xue@1 716 }//GICP
xue@1 717
xue@1 718 //---------------------------------------------------------------------------
xue@1 719 /*
xue@1 720 function GILT: inv(lower trangular of A)->lower trangular of A
xue@1 721
xue@1 722 In: matrix A[N][N]
xue@1 723 Out: matrix A[N][N]
xue@1 724
xue@1 725 Returns the determinant of the lower trangular of A
xue@1 726 */
xue@1 727 double GILT(int N, double** A)
xue@1 728 {
xue@1 729 double result=1;
xue@1 730 A[0][0]=1/A[0][0];
xue@1 731 for (int i=1; i<N; i++)
xue@1 732 {
xue@1 733 result*=A[i][i];
xue@1 734 double tmp=1/A[i][i];
xue@1 735 for (int k=0; k<i; k++) A[i][k]*=tmp; A[i][i]=tmp;
xue@1 736 for (int j=0; j<i; j++)
xue@1 737 {
xue@1 738 double tmp2=A[i][j];
xue@1 739 for (int k=0; k<j; k++) A[i][k]-=A[j][k]*tmp2; A[i][j]=-A[j][j]*tmp2;
xue@1 740 }
xue@1 741 }
xue@1 742 return result;
xue@1 743 }//GILT
xue@1 744
xue@1 745 /*
xue@1 746 function GIUT: inv(upper trangular of A)->upper trangular of A
xue@1 747
xue@1 748 In: matrix A[N][N]
xue@1 749 Out: matrix A[N][N]
xue@1 750
xue@1 751 Returns the determinant of the upper trangular of A
xue@1 752 */
xue@1 753 double GIUT(int N, double** A)
xue@1 754 {
xue@1 755 double result=1;
xue@1 756 A[0][0]=1/A[0][0];
xue@1 757 for (int i=1; i<N; i++)
xue@1 758 {
xue@1 759 result*=A[i][i];
xue@1 760 double tmp=1/A[i][i];
xue@1 761 for (int k=0; k<i; k++) A[k][i]*=tmp; A[i][i]=tmp;
xue@1 762 for (int j=0; j<i; j++)
xue@1 763 {
xue@1 764 double tmp2=A[j][i];
xue@1 765 for (int k=0; k<j; k++) A[k][i]-=A[k][j]*tmp2; A[j][i]=-A[j][j]*tmp2;
xue@1 766 }
xue@1 767 }
xue@1 768 return result;
xue@1 769 }//GIUT
xue@1 770
xue@1 771 //---------------------------------------------------------------------------
xue@1 772 /*
xue@1 773 function GISCP: matrix inverse using Gaussian elimination w. scaled column pivoting: inv(A)->A.
xue@1 774
xue@1 775 In: matrix A[N][N]
xue@1 776 Out: matrix A[N][N]
xue@1 777
xue@1 778 Returns the determinant of the inverse matrix, 0 on failure.
xue@1 779 */
xue@1 780 double GISCP(int N, double** A)
xue@1 781 {
xue@1 782 int c, p, ip, *rp=new int[N]; for (int i=0; i<N; i++) rp[i]=i;
xue@1 783 double m, result=1, *s=new double[N];
xue@1 784
xue@1 785 for (int i=0; i<N; i++)
xue@1 786 {
xue@1 787 s[i]=A[i][0];
xue@1 788 for (int j=1; j<N; j++) if (fabs(s[i])<fabs(A[i][j])) s[i]=A[i][j];
xue@1 789 if (s[i]==0) {delete[] s; delete[] rp; return 0;}
xue@1 790 rp[i]=i;
xue@1 791 }
xue@1 792
xue@1 793 //Gaussian eliminating
xue@1 794 for (int i=0; i<N-1; i++)
xue@1 795 {
xue@1 796 p=i, ip=i+1;
xue@1 797 while (ip<N){if (fabs(A[rp[ip]][i]/s[rp[ip]])>fabs(A[rp[p]][i]/s[rp[p]])) p=ip; ip++;}
xue@1 798 if (A[rp[p]][i]==0) {delete[] s; delete[] rp; return 0;}
xue@1 799 if (p!=i) {c=rp[i]; rp[i]=rp[p]; rp[p]=c; result=-result;}
xue@1 800 result/=A[rp[i]][i];
xue@1 801 for (int j=i+1; j<N; j++)
xue@1 802 {
xue@1 803 m=A[rp[j]][i]/A[rp[i]][i];
xue@1 804 A[rp[j]][i]=-m;
xue@1 805 for (int k=i+1; k<N; k++) A[rp[j]][k]-=m*A[rp[i]][k];
xue@1 806 for (int k=0; k<i; k++) A[rp[j]][k]-=m*A[rp[i]][k];
xue@1 807 }
xue@1 808 }
xue@1 809 if (A[rp[N-1]][N-1]==0) {delete[] s; delete[] rp; return 0;}
xue@1 810 result/=A[rp[N-1]][N-1];
xue@1 811 //backward substitution
xue@1 812 for (int i=0; i<N-1; i++)
xue@1 813 {
xue@1 814 m=A[rp[i]][i]; for (int k=0; k<N; k++) A[rp[i]][k]/=m; A[rp[i]][i]=1/m;
xue@1 815 for (int j=i+1; j<N; j++)
xue@1 816 {
xue@1 817 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;
xue@1 818 }
xue@1 819 }
xue@1 820 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;
xue@1 821 //recover column and row exchange
xue@1 822 double* tm=new double[N]; int sizeN=sizeof(double)*N;
xue@1 823 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); }
xue@1 824 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];}
xue@1 825
xue@1 826 delete[] tm; delete[] s; delete[] rp;
xue@1 827 return result;
xue@1 828 }//GISCP
xue@1 829
xue@1 830 /*
xue@1 831 function GISCP: wrapper function that does not overwrite input matrix A: inv(A)->X.
xue@1 832
xue@1 833 In: matrix A[N][N]
xue@1 834 Out: matrix X[N][N]
xue@1 835
xue@1 836 Returns the determinant of the inverse matrix, 0 on failure.
xue@1 837 */
xue@1 838 double GISCP(int N, double** X, double** A)
xue@1 839 {
xue@1 840 Copy(N, X, A);
xue@1 841 return GISCP(N, X);
xue@1 842 }//GISCP
xue@1 843
xue@1 844 //---------------------------------------------------------------------------
xue@1 845 /*
xue@1 846 function GSI: Gaussian-Seidel iterative algorithm for solving linear system Ax=b. Breaks down if any
xue@1 847 Aii=0, like the Jocobi method JI(...).
xue@1 848
xue@1 849 Gaussian-Seidel iteration is x(k)=(D-L)^(-1)(Ux(k-1)+b), where D is diagonal, L is lower triangular,
xue@1 850 U is upper triangular and A=L+D+U.
xue@1 851
xue@1 852 In: matrix A[N][N], vector b[N], initial vector x0[N]
xue@1 853 Out: vector x0[N]
xue@1 854
xue@1 855 Returns 0 is successful. Contents of matrix A and vector b remain unchanged on return.
xue@1 856 */
xue@1 857 int GSI(int N, double* x0, double** A, double* b, double ep, int maxiter)
xue@1 858 {
xue@1 859 double e, *x=new double[N];
xue@1 860 int k=0, sizeN=sizeof(double)*N;
xue@1 861 while (k<maxiter)
xue@1 862 {
xue@1 863 for (int i=0; i<N; i++)
xue@1 864 {
xue@1 865 x[i]=b[i];
xue@1 866 for (int j=0; j<i; j++) x[i]-=A[i][j]*x[j];
xue@1 867 for (int j=i+1; j<N; j++) x[i]-=A[i][j]*x0[j];
xue@1 868 x[i]/=A[i][i];
xue@1 869 }
xue@1 870 e=0; for (int j=0; j<N; j++) e+=fabs(x[j]-x0[j]);
xue@1 871 memcpy(x0, x, sizeN);
xue@1 872 if (e<ep) break;
xue@1 873 k++;
xue@1 874 }
xue@1 875 delete[] x;
xue@1 876 if (k>=maxiter) return 1;
xue@1 877 return 0;
xue@1 878 }//GSI
xue@1 879
xue@1 880 //---------------------------------------------------------------------------
xue@1 881 /*
xue@1 882 function Hessenb: reducing a square matrix A to upper Hessenberg form
xue@1 883
xue@1 884 In: matrix A[N][N]
xue@1 885 Out: matrix A[N][N], in upper Hessenberg form
xue@1 886
xue@1 887 No return value.
xue@1 888 */
xue@1 889 void Hessenb(int N, double** A)
xue@1 890 {
xue@1 891 double x, y;
xue@1 892 for (int m=1; m<N-1; m++)
xue@1 893 {
xue@1 894 x=0;
xue@1 895 int i=m;
xue@1 896 for (int j=m; j<N; j++)
xue@1 897 {
xue@1 898 if (fabs(A[j][m-1]) > fabs(x))
xue@1 899 {
xue@1 900 x=A[j][m-1];
xue@1 901 i=j;
xue@1 902 }
xue@1 903 }
xue@1 904 if (i!=m)
xue@1 905 {
xue@1 906 for (int j=m-1; j<N; j++)
xue@1 907 {
xue@1 908 double tmp=A[i][j];
xue@1 909 A[i][j]=A[m][j];
xue@1 910 A[m][j]=tmp;
xue@1 911 }
xue@1 912 for (int j=0; j<N; j++)
xue@1 913 {
xue@1 914 double tmp=A[j][i];
xue@1 915 A[j][i]=A[j][m];
xue@1 916 A[j][m]=tmp;
xue@1 917 }
xue@1 918 }
xue@1 919 if (x!=0)
xue@1 920 {
xue@1 921 for (i=m+1; i<N; i++)
xue@1 922 {
xue@1 923 if ((y=A[i][m-1])!=0)
xue@1 924 {
xue@1 925 y/=x;
xue@1 926 A[i][m-1]=0;
xue@1 927 for (int j=m; j<N; j++) A[i][j]-=y*A[m][j];
xue@1 928 for (int j=0; j<N; j++) A[j][m]+=y*A[j][i];
xue@1 929 }
xue@1 930 }
xue@1 931 }
xue@1 932 }
xue@1 933 }//Hessenb
xue@1 934
xue@1 935 //---------------------------------------------------------------------------
xue@1 936 /*
xue@1 937 function HouseHolder: house holder method converting a symmetric matrix into a tridiagonal symmetric
xue@1 938 matrix, or a non-symmetric matrix into an upper-Hessenberg matrix, using similarity transformation.
xue@1 939
xue@1 940 In: matrix A[N][N]
xue@1 941 Out: matrix A[N][N] after transformation
xue@1 942
xue@1 943 No return value.
xue@1 944 */
xue@1 945 void HouseHolder(int N, double** A)
xue@1 946 {
xue@1 947 double q, alf, prod, r2, *v=new double[N], *u=new double[N], *z=new double[N];
xue@1 948 for (int k=0; k<N-2; k++)
xue@1 949 {
xue@1 950 q=Inner(N-1-k, &A[k][k+1], &A[k][k+1]);
xue@1 951
xue@1 952 if (A[k][k+1]==0) alf=sqrt(q);
xue@1 953 else alf=-sqrt(q)*A[k+1][k]/fabs(A[k+1][k]);
xue@1 954
xue@1 955 r2=alf*(alf-A[k+1][k]);
xue@1 956
xue@1 957 v[k]=0; v[k+1]=A[k][k+1]-alf;
xue@1 958 memcpy(&v[k+2], &A[k][k+2], sizeof(double)*(N-k-2));
xue@1 959
xue@1 960 for (int j=k; j<N; j++) u[j]=Inner(N-1-k, &A[j][k+1], &v[k+1])/r2;
xue@1 961
xue@1 962 prod=Inner(N-1-k, &v[k+1], &u[k+1]);
xue@1 963
xue@1 964 MultiAdd(N-k, &z[k], &u[k], &v[k], -prod/2/r2);
xue@1 965
xue@1 966 for (int l=k+1; l<N-1; l++)
xue@1 967 {
xue@1 968 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];
xue@1 969 A[l][l]=A[l][l]-2*v[l]*z[l];
xue@1 970 }
xue@1 971
xue@1 972 A[N-1][N-1]=A[N-1][N-1]-2*v[N-1]*z[N-1];
xue@1 973
xue@1 974 for (int j=k+2; j<N; j++) A[k][j]=A[j][k]=0;
xue@1 975
xue@1 976 A[k][k+1]=A[k+1][k]=A[k+1][k]-v[k+1]*z[k];
xue@1 977 }
xue@1 978 delete[] u; delete[] v; delete[] z;
xue@1 979 }//HouseHolder
xue@1 980
xue@1 981 /*
xue@1 982 function HouseHolder: house holder transformation T=Q'AQ or A=QTQ', where T is tridiagonal and Q is
xue@1 983 unitary i.e. QQ'=I.
xue@1 984
xue@1 985 In: matrix A[N][N]
xue@1 986 Out: matrix tridiagonal matrix T[N][N] and unitary matrix Q[N][N]
xue@1 987
xue@1 988 No return value. Identical A and T allowed. Content of matrix A is unchanged if A!=T.
xue@1 989 */
xue@1 990 void HouseHolder(int N, double** T, double** Q, double** A)
xue@1 991 {
xue@1 992 double g, alf, prod, r2, *v=new double[N], *u=new double[N], *z=new double[N];
xue@1 993 int sizeN=sizeof(double)*N;
xue@1 994 if (T!=A) for (int i=0; i<N; i++) memcpy(T[i], A[i], sizeN);
xue@1 995 for (int i=0; i<N; i++) {memset(Q[i], 0, sizeN); Q[i][i]=1;}
xue@1 996 for (int k=0; k<N-2; k++)
xue@1 997 {
xue@1 998 g=Inner(N-1-k, &T[k][k+1], &T[k][k+1]);
xue@1 999
xue@1 1000 if (T[k][k+1]==0) alf=sqrt(g);
xue@1 1001 else alf=-sqrt(g)*T[k+1][k]/fabs(T[k+1][k]);
xue@1 1002
xue@1 1003 r2=alf*(alf-T[k+1][k]);
xue@1 1004
xue@1 1005 v[k]=0; v[k+1]=T[k][k+1]-alf;
xue@1 1006 memcpy(&v[k+2], &T[k][k+2], sizeof(double)*(N-k-2));
xue@1 1007
xue@1 1008 for (int j=k; j<N; j++) u[j]=Inner(N-1-k, &T[j][k+1], &v[k+1])/r2;
xue@1 1009
xue@1 1010 prod=Inner(N-1-k, &v[k+1], &u[k+1]);
xue@1 1011
xue@1 1012 MultiAdd(N-k, &z[k], &u[k], &v[k], -prod/2/r2);
xue@1 1013
xue@1 1014 for (int l=k+1; l<N-1; l++)
xue@1 1015 {
xue@1 1016 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];
xue@1 1017 T[l][l]=T[l][l]-2*v[l]*z[l];
xue@1 1018 }
xue@1 1019
xue@1 1020 T[N-1][N-1]=T[N-1][N-1]-2*v[N-1]*z[N-1];
xue@1 1021
xue@1 1022 for (int j=k+2; j<N; j++) T[k][j]=T[j][k]=0;
xue@1 1023
xue@1 1024 T[k][k+1]=T[k+1][k]=T[k+1][k]-v[k+1]*z[k];
xue@1 1025
xue@1 1026 for (int i=0; i<N; i++)
xue@1 1027 MultiAdd(N-k, &Q[i][k], &Q[i][k], &v[k], -Inner(N-k, &Q[i][k], &v[k])/r2);
xue@1 1028 }
xue@1 1029 delete[] u; delete[] v; delete[] z;
xue@1 1030 }//HouseHolder
xue@1 1031
xue@1 1032 /*
xue@1 1033 function HouseHolder: nr version of householder method for transforming symmetric matrix A to QTQ',
xue@1 1034 where T is tridiagonal and Q is orthonormal.
xue@1 1035
xue@1 1036 In: matrix A[N][N]
xue@1 1037 Out: A[N][N]: now containing Q
xue@1 1038 d[N]: containing diagonal elements of T
xue@1 1039 sd[N]: containing subdiagonal elements of T as sd[1:N-1].
xue@1 1040
xue@1 1041 No return value.
xue@1 1042 */
xue@1 1043 void HouseHolder(int N, double **A, double* d, double* sd)
xue@1 1044 {
xue@1 1045 for (int i=N-1; i>=1; i--)
xue@1 1046 {
xue@1 1047 int l=i-1;
xue@1 1048 double h=0, scale=0;
xue@1 1049 if (l>0)
xue@1 1050 {
xue@1 1051 for (int k=0; k<=l; k++) scale+=fabs(A[i][k]);
xue@1 1052 if (scale==0.0) sd[i]=A[i][l];
xue@1 1053 else
xue@1 1054 {
xue@1 1055 for (int k=0; k<=l; k++)
xue@1 1056 {
xue@1 1057 A[i][k]/=scale;
xue@1 1058 h+=A[i][k]*A[i][k];
xue@1 1059 }
xue@1 1060 double f=A[i][l];
xue@1 1061 double g=(f>=0?-sqrt(h): sqrt(h));
xue@1 1062 sd[i]=scale*g;
xue@1 1063 h-=f*g;
xue@1 1064 A[i][l]=f-g;
xue@1 1065 f=0;
xue@1 1066 for (int j=0; j<=l; j++)
xue@1 1067 {
xue@1 1068 A[j][i]=A[i][j]/h;
xue@1 1069 g=0;
xue@1 1070 for (int k=0; k<=j; k++) g+=A[j][k]*A[i][k];
xue@1 1071 for (int k=j+1; k<=l; k++) g+=A[k][j]*A[i][k];
xue@1 1072 sd[j]=g/h;
xue@1 1073 f+=sd[j]*A[i][j];
xue@1 1074 }
xue@1 1075 double hh=f/(h+h);
xue@1 1076 for (int j=0; j<=l; j++)
xue@1 1077 {
xue@1 1078 f=A[i][j];
xue@1 1079 sd[j]=g=sd[j]-hh*f;
xue@1 1080 for (int k=0; k<=j; k++) A[j][k]-=(f*sd[k]+g*A[i][k]);
xue@1 1081 }
xue@1 1082 }
xue@1 1083 }
xue@1 1084 else
xue@1 1085 sd[i]=A[i][l];
xue@1 1086 d[i]=h;
xue@1 1087 }
xue@1 1088
xue@1 1089 d[0]=sd[0]=0;
xue@1 1090
xue@1 1091 for (int i=0; i<N; i++)
xue@1 1092 {
xue@1 1093 int l=i-1;
xue@1 1094 if (d[i])
xue@1 1095 {
xue@1 1096 for (int j=0; j<=l; j++)
xue@1 1097 {
xue@1 1098 double g=0.0;
xue@1 1099 for (int k=0; k<=l; k++) g+=A[i][k]*A[k][j];
xue@1 1100 for (int k=0; k<=l; k++) A[k][j]-=g*A[k][i];
xue@1 1101 }
xue@1 1102 }
xue@1 1103 d[i]=A[i][i];
xue@1 1104 A[i][i]=1.0;
xue@1 1105 for (int j=0; j<=l; j++) A[j][i]=A[i][j]=0.0;
xue@1 1106 }
xue@1 1107 }//HouseHolder
xue@1 1108
xue@1 1109 //---------------------------------------------------------------------------
xue@1 1110 /*
xue@1 1111 function Inner: inner product z=y'x
xue@1 1112
xue@1 1113 In: vectors x[N], y[N]
xue@1 1114
xue@1 1115 Returns inner product of x and y.
xue@1 1116 */
xue@1 1117 double Inner(int N, double* x, double* y)
xue@1 1118 {
xue@1 1119 double result=0;
xue@1 1120 for (int i=0; i<N; i++) result+=x[i]*y[i];
xue@1 1121 return result;
xue@1 1122 }//Inner
xue@1 1123 //complex versions
xue@1 1124 cdouble Inner(int N, double* x, cdouble* y)
xue@1 1125 {
xue@1 1126 cdouble result=0;
xue@1 1127 for (int i=0; i<N; i++) result+=x[i]**y[i];
xue@1 1128 return result;
xue@1 1129 }//Inner
xue@1 1130 cdouble Inner(int N, cdouble* x, cdouble* y)
xue@1 1131 {
xue@1 1132 cdouble result=0;
xue@1 1133 for (int i=0; i<N; i++) result+=x[i]^y[i];
xue@1 1134 return result;
xue@1 1135 }//Inner
xue@1 1136 cdouble Inner(int N, cfloat* x, cdouble* y)
xue@1 1137 {
xue@1 1138 cdouble result=0;
xue@1 1139 for (int i=0; i<N; i++) result+=x[i]^y[i];
xue@1 1140 return result;
xue@1 1141 }//Inner
xue@1 1142 cfloat Inner(int N, cfloat* x, cfloat* y)
xue@1 1143 {
xue@1 1144 cfloat result=0;
xue@1 1145 for (int i=0; i<N; i++) result+=x[i]^y[i];
xue@1 1146 return result;
xue@1 1147 }//Inner
xue@1 1148
xue@1 1149 /*
xue@1 1150 function Inner: inner product z=tr(Y'X)
xue@1 1151
xue@1 1152 In: matrices X[M][N], Y[M][N]
xue@1 1153
xue@1 1154 Returns inner product of X and Y.
xue@1 1155 */
xue@1 1156 double Inner(int M, int N, double** X, double** Y)
xue@1 1157 {
xue@1 1158 double result=0;
xue@1 1159 for (int m=0; m<M; m++) for (int n=0; n<N; n++) result+=X[m][n]*Y[m][n];
xue@1 1160 return result;
xue@1 1161 }//Inner
xue@1 1162
xue@1 1163 //---------------------------------------------------------------------------
xue@1 1164 /*
xue@1 1165 function JI: Jacobi interative algorithm for solving linear system Ax=b Breaks down if A[i][i]=0 for
xue@1 1166 any i. Reorder A so that this does not happen.
xue@1 1167
xue@1 1168 Jacobi iteration is x(k)=D^(-1)((L+U)x(k-1)+b), D is diagonal, L is lower triangular, U is upper
xue@1 1169 triangular and A=L+D+U.
xue@1 1170
xue@1 1171 In: matrix A[N][N], vector b[N], initial vector x0[N]
xue@1 1172 Out: vector x0[N]
xue@1 1173
xue@1 1174 Returns 0 if successful. Contents of matrix A and vector b are unchanged on return.
xue@1 1175 */
xue@1 1176 int JI(int N, double* x0, double** A, double* b, double ep, int maxiter)
xue@1 1177 {
xue@1 1178 double e, *x=new double[N];
xue@1 1179 int k=0, sizeN=sizeof(double)*N;
xue@1 1180 while (k<maxiter)
xue@1 1181 {
xue@1 1182 for (int i=0; i<N; i++)
xue@1 1183 {
xue@1 1184 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];
xue@1 1185 }
xue@1 1186 e=0; for (int j=0; j<N; j++) e+=fabs(x[j]-x0[j]); //inf-norm used here
xue@1 1187 memcpy(x0, x, sizeN);
xue@1 1188 if (e<ep) break;
xue@1 1189 k++;
xue@1 1190 }
xue@1 1191 delete[] x;
xue@1 1192 if (k>=maxiter) return 1;
xue@1 1193 else return 0;
xue@1 1194 }//JI
xue@1 1195
xue@1 1196 //---------------------------------------------------------------------------
xue@1 1197 /*
xue@1 1198 function LDL: LDL' decomposition A=LDL', where L is lower triangular and D is diagonal identical l and
xue@1 1199 a allowed.
xue@1 1200
xue@1 1201 The symmetric matrix A is positive definite iff A can be factorized as LDL', where L is lower
xue@1 1202 triangular with ones on its diagonal and D is diagonal with positive diagonal entries.
xue@1 1203
xue@1 1204 If a symmetric matrix A can be reduced by Gaussian elimination without row interchanges, then it can
xue@1 1205 be factored into LDL', where L is lower triangular with ones on its diagonal and D is diagonal with
xue@1 1206 non-zero diagonal entries.
xue@1 1207
xue@1 1208 In: matrix A[N][N]
xue@1 1209 Out: lower triangular matrix L[N][N], vector d[N] containing diagonal elements of D
xue@1 1210
xue@1 1211 Returns 0 if successful. Content of matrix A is unchanged on return.
xue@1 1212 */
xue@1 1213 int LDL(int N, double** L, double* d, double** A)
xue@1 1214 {
xue@1 1215 double* v=new double[N];
xue@1 1216
xue@1 1217 if (A[0][0]==0) {delete[] v; return 1;}
xue@1 1218 d[0]=A[0][0]; for (int j=1; j<N; j++) L[j][0]=A[j][0]/d[0];
xue@1 1219 for (int i=1; i<N; i++)
xue@1 1220 {
xue@1 1221 for (int j=0; j<i; j++) v[j]=L[i][j]*d[j];
xue@1 1222 d[i]=A[i][i]; for (int j=0; j<i; j++) d[i]-=L[i][j]*v[j];
xue@1 1223 if (d[i]==0) {delete[] v; return 1;}
xue@1 1224 for (int j=i+1; j<N; j++)
xue@1 1225 {
xue@1 1226 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];
xue@1 1227 }
xue@1 1228 }
xue@1 1229 delete[] v;
xue@1 1230
xue@1 1231 for (int i=0; i<N; i++) {L[i][i]=1; memset(&L[i][i+1], 0, sizeof(double)*(N-1-i));}
xue@1 1232 return 0;
xue@1 1233 }//LDL
xue@1 1234
xue@1 1235 //---------------------------------------------------------------------------
xue@1 1236 /*
xue@1 1237 function LQ_GS: LQ decomposition using Gram-Schmidt method
xue@1 1238
xue@1 1239 In: matrix A[M][N], M<=N
xue@1 1240 Out: matrices L[M][M], Q[M][N]
xue@1 1241
xue@1 1242 No return value.
xue@1 1243 */
xue@1 1244 void LQ_GS(int M, int N, double** A, double** L, double** Q)
xue@1 1245 {
xue@1 1246 double *u=new double[N];
xue@1 1247 for (int m=0; m<M; m++)
xue@1 1248 {
xue@1 1249 memset(L[m], 0, sizeof(double)*M);
xue@1 1250 memcpy(u, A[m], sizeof(double)*N);
xue@1 1251 for (int k=0; k<m; k++)
xue@1 1252 {
xue@1 1253 double ip=0; for (int n=0; n<N; n++) ip+=Q[k][n]*u[n];
xue@1 1254 for (int n=0; n<N; n++) u[n]-=ip*Q[k][n];
xue@1 1255 L[m][k]=ip;
xue@1 1256 }
xue@1 1257 double iu=0; for (int n=0; n<N; n++) iu+=u[n]*u[n]; iu=sqrt(iu);
xue@1 1258 L[m][m]=iu; iu=1.0/iu;
xue@1 1259 for (int n=0; n<N; n++) Q[m][n]=u[n]*iu;
xue@1 1260 }
xue@1 1261 delete[] u;
xue@1 1262 }//LQ_GS
xue@1 1263
xue@1 1264 //---------------------------------------------------------------------------
xue@1 1265 /*
xue@1 1266 function LSLinear2: 2-dtage LS solution of A[M][N]x[N][1]=y[M][1], M>=N. Use of this function requires
xue@1 1267 the submatrix A[N][N] be invertible.
xue@1 1268
xue@1 1269 In: matrix A[M][N], vector y[M], M>=N.
xue@1 1270 Out: vector x[N].
xue@1 1271
xue@1 1272 No return value. Contents of matrix A and vector y are unchanged on return.
xue@1 1273 */
xue@1 1274 void LSLinear2(int M, int N, double* x, double** A, double* y)
xue@1 1275 {
xue@1 1276 double** A1=Copy(N, N, 0, A);
xue@1 1277 LU(N, x, A1, y);
xue@1 1278 if (M>N)
xue@1 1279 {
xue@1 1280 double** B=&A[N];
xue@1 1281 double* Del=MultiplyXy(M-N, N, B, x);
xue@1 1282 MultiAdd(M-N, Del, Del, &y[N], -1);
xue@1 1283 double** A2=MultiplyXtX(N, N, A);
xue@1 1284 MultiplyXtX(N, M-N, A1, B);
xue@1 1285 MultiAdd(N, N, A2, A2, A1, 1);
xue@1 1286 double* b2=MultiplyXty(N, M-N, B, Del);
xue@1 1287 double* dx=new double[N];
xue@1 1288 GESCP(N, dx, A2, b2);
xue@1 1289 MultiAdd(N, x, x, dx, -1);
xue@1 1290 delete[] dx;
xue@1 1291 delete[] Del;
xue@1 1292 delete[] b2;
xue@1 1293 DeAlloc2(A2);
xue@1 1294 }
xue@1 1295 DeAlloc2(A1);
xue@1 1296 }//LSLinear2
xue@1 1297
xue@1 1298 //---------------------------------------------------------------------------
xue@1 1299 /*
xue@1 1300 function LU: LU decomposition A=LU, where L is lower triangular with diagonal entries 1 and U is upper
xue@1 1301 triangular.
xue@1 1302
xue@1 1303 LU is possible if A can be reduced by Gaussian elimination without row interchanges.
xue@1 1304
xue@1 1305 In: matrix A[N][N]
xue@1 1306 Out: matrices L[N][N] and U[N][N], subject to input values of L and U:
xue@1 1307 if L euqals NULL, L is not returned
xue@1 1308 if U equals NULL or A, U is returned in A, s.t. A is modified
xue@1 1309 if L equals A, L is returned in A, s.t. A is modified
xue@1 1310 if L equals U, L and U are returned in the same matrix
xue@1 1311 when L and U are returned in the same matrix, diagonal of L (all 1) is not returned
xue@1 1312
xue@1 1313 Returns 0 if successful.
xue@1 1314 */
xue@1 1315 int LU(int N, double** L, double** U, double** A)
xue@1 1316 {
xue@1 1317 double* diagl=new double[N];
xue@1 1318 for (int i=0; i<N; i++) diagl[i]=1;
xue@1 1319
xue@1 1320 int sizeN=sizeof(double)*N;
xue@1 1321 if (U==0) U=A;
xue@1 1322 if (U!=A) for (int i=0; i<N; i++) memcpy(U[i], A[i], sizeN);
xue@1 1323 int result=LU_Direct(0, N, diagl, U);
xue@1 1324 if (result==0)
xue@1 1325 {
xue@1 1326 if (L!=U)
xue@1 1327 {
xue@1 1328 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));}
xue@1 1329 for (int i=1; i<N; i++) memset(U[i], 0, sizeof(double)*i);
xue@1 1330 }
xue@1 1331 }
xue@1 1332 delete[] diagl;
xue@1 1333 return result;
xue@1 1334 }//LU
xue@1 1335
xue@1 1336 /*
xue@1 1337 function LU: Solving linear system Ax=y by LU factorization
xue@1 1338
xue@1 1339 In: matrix A[N][N], vector y[N]
xue@1 1340 Out: x[N]
xue@1 1341
xue@1 1342 No return value. On return A contains its LU factorization (with pivoting, diag mode 1), y remains
xue@1 1343 unchanged.
xue@1 1344 */
xue@1 1345 void LU(int N, double* x, double** A, double* y, int* ind)
xue@1 1346 {
xue@1 1347 int parity;
xue@1 1348 bool allocind=!ind;
xue@1 1349 if (allocind) ind=new int[N];
xue@1 1350 LUCP(A, N, ind, parity, 1);
xue@1 1351 for (int i=0; i<N; i++) x[i]=y[ind[i]];
xue@1 1352 for (int i=0; i<N; i++)
xue@1 1353 {
xue@1 1354 for (int j=i+1; j<N; j++) x[j]=x[j]-x[i]*A[j][i];
xue@1 1355 }
xue@1 1356 for (int i=N-1; i>=0; i--)
xue@1 1357 {
xue@1 1358 x[i]/=A[i][i];
xue@1 1359 for (int j=0; j<i; j++) x[j]=x[j]-x[i]*A[j][i];
xue@1 1360 }
xue@1 1361 if (allocind) delete[] ind;
xue@1 1362 }//LU
xue@1 1363
xue@1 1364 //---------------------------------------------------------------------------
xue@1 1365 /*
xue@1 1366 LU_DiagL shows the original procedure for calculating A=LU in separate buffers substitute l and u by a
xue@1 1367 gives the stand-still method LU_Direct().
xue@1 1368 *//*
xue@1 1369 void LU_DiagL(int N, double** l, double* diagl, double** u, double** a)
xue@1 1370 {
xue@1 1371 l[0][0]=diagl[0]; u[0][0]=a[0][0]/l[0][0]; //here to signal failure if l[00]u[00]=0
xue@1 1372 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];
xue@1 1373 memset(&l[0][1], 0, sizeof(double)*(N-1));
xue@1 1374 for (int i=1; i<N-1; i++)
xue@1 1375 {
xue@1 1376 l[i][i]=diagl[i];
xue@1 1377 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
xue@1 1378 for (int j=i+1; j<N; j++)
xue@1 1379 {
xue@1 1380 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];
xue@1 1381 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];
xue@1 1382 }
xue@1 1383 memset(&l[i][i+1], 0, sizeof(double)*(N-1-i)), memset(u[i], 0, sizeof(double)*i);
xue@1 1384 }
xue@1 1385 l[N-1][N-1]=diagl[N-1];
xue@1 1386 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];
xue@1 1387 memset(u[N-1], 0, sizeof(double)*(N-1));
xue@1 1388 } //LU_DiagL*/
xue@1 1389
xue@1 1390 //---------------------------------------------------------------------------
xue@1 1391 /*
xue@1 1392 function LU_Direct: LU factorization A=LU.
xue@1 1393
xue@1 1394 In: matrix A[N][N], vector diag[N] specifying main diagonal of L or U, according to mode (0=LDiag,
xue@1 1395 1=UDiag).
xue@1 1396 Out: matrix A[N][N] now containing L and U.
xue@1 1397
xue@1 1398 Returns 0 if successful.
xue@1 1399 */
xue@1 1400 int LU_Direct(int mode, int N, double* diag, double** A)
xue@1 1401 {
xue@1 1402 if (mode==0)
xue@1 1403 {
xue@1 1404 if (A[0][0]==0) return 1;
xue@1 1405 A[0][0]=A[0][0]/diag[0];
xue@1 1406 for (int j=1; j<N; j++) A[0][j]=A[0][j]/diag[0], A[j][0]=A[j][0]/A[0][0];
xue@1 1407 for (int i=1; i<N-1; i++)
xue@1 1408 {
xue@1 1409 for (int k=0; k<i; k++) A[i][i]-=A[i][k]*A[k][i]; A[i][i]/=diag[i];
xue@1 1410 if (A[i][i]==0) return 2;
xue@1 1411 for (int j=i+1; j<N; j++)
xue@1 1412 {
xue@1 1413 for (int k=0; k<i; k++) A[i][j]-=A[i][k]*A[k][j]; A[i][j]/=diag[i];
xue@1 1414 for (int k=0; k<i; k++) A[j][i]-=A[j][k]*A[k][i]; A[j][i]/=A[i][i];
xue@1 1415 }
xue@1 1416 }
xue@1 1417 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];
xue@1 1418 }
xue@1 1419 else if (mode==1)
xue@1 1420 {
xue@1 1421 A[0][0]=A[0][0]/diag[0];
xue@1 1422 if (A[0][0]==0) return 1;
xue@1 1423 for (int j=1; j<N; j++) A[0][j]=A[0][j]/A[0][0], A[j][0]=A[j][0]/diag[0];
xue@1 1424 for (int i=1; i<N-1; i++)
xue@1 1425 {
xue@1 1426 for (int k=0; k<i; k++) A[i][i]-=A[i][k]*A[k][i]; A[i][i]/=diag[i];
xue@1 1427 if (A[i][i]==0) return 2;
xue@1 1428 for (int j=i+1; j<N; j++)
xue@1 1429 {
xue@1 1430 for (int k=0; k<i; k++) A[i][j]-=A[i][k]*A[k][j]; A[i][j]/=A[i][i];
xue@1 1431 for (int k=0; k<i; k++) A[j][i]-=A[j][k]*A[k][i]; A[j][i]/=diag[i];
xue@1 1432 }
xue@1 1433 }
xue@1 1434 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];
xue@1 1435 }
xue@1 1436 return 0;
xue@1 1437 }//LU_Direct
xue@1 1438
xue@1 1439 //---------------------------------------------------------------------------
xue@1 1440 /*
xue@1 1441 function LU_PD: LU factorization for pentadiagonal A=LU
xue@1 1442
xue@1 1443 In: pentadiagonal matrix A[N][N] stored in a compact format, i.e. A[i][j]->b[i-j, j]
xue@1 1444 the main diagonal is b[0][0]~b[0][N-1]
xue@1 1445 the 1st upper subdiagonal is b[-1][1]~b[-1][N-1]
xue@1 1446 the 2nd upper subdiagonal is b[-2][2]~b[-2][N-1]
xue@1 1447 the 1st lower subdiagonal is b[1][0]~b[1][N-2]
xue@1 1448 the 2nd lower subdiagonal is b[2][0]~b[2][N-3]
xue@1 1449
xue@1 1450 Out: L[N][N] and U[N][N], main diagonal of L being all 1 (probably), stored in a compact format in
xue@1 1451 b[-2:2][N].
xue@1 1452
xue@1 1453 Returns 0 if successful.
xue@1 1454 */
xue@1 1455 int LU_PD(int N, double** b)
xue@1 1456 {
xue@1 1457 if (b[0][0]==0) return 1;
xue@1 1458 b[1][0]/=b[0][0], b[2][0]/=b[0][0];
xue@1 1459
xue@1 1460 //i=1, not to double b[*][i-2], b[-2][i]
xue@1 1461 b[0][1]-=b[1][0]*b[-1][1];
xue@1 1462 if (b[0][1]==0) return 2;
xue@1 1463 b[-1][2]-=b[1][0]*b[-2][2];
xue@1 1464 b[1][1]-=b[2][0]*b[-1][1];
xue@1 1465 b[1][1]/=b[0][1];
xue@1 1466 b[2][1]/=b[0][1];
xue@1 1467
xue@1 1468 for (int i=2; i<N-2; i++)
xue@1 1469 {
xue@1 1470 b[0][i]-=b[2][i-2]*b[-2][i];
xue@1 1471 b[0][i]-=b[1][i-1]*b[-1][i];
xue@1 1472 if (b[0][i]==0) return 2;
xue@1 1473 b[-1][i+1]-=b[1][i-1]*b[-2][i+1];
xue@1 1474 b[1][i]-=b[2][i-1]*b[-1][i];
xue@1 1475 b[1][i]/=b[0][i];
xue@1 1476 b[2][i]/=b[0][i];
xue@1 1477 }
xue@1 1478 //i=N-2, not to tough b[2][i]
xue@1 1479 b[0][N-2]-=b[2][N-4]*b[-2][N-2];
xue@1 1480 b[0][N-2]-=b[1][N-3]*b[-1][N-2];
xue@1 1481 if (b[0][N-2]==0) return 2;
xue@1 1482 b[-1][N-1]-=b[1][N-3]*b[-2][N-1];
xue@1 1483 b[1][N-2]-=b[2][N-3]*b[-1][N-2];
xue@1 1484 b[1][N-2]/=b[0][N-2];
xue@1 1485
xue@1 1486 b[0][N-1]-=b[2][N-3]*b[-2][N-1];
xue@1 1487 b[0][N-1]-=b[1][N-2]*b[-1][N-1];
xue@1 1488 return 0;
xue@1 1489 }//LU_PD
xue@1 1490
xue@1 1491 /*
xue@1 1492 This old version is kept here as a reference.
xue@1 1493 *//*
xue@1 1494 int LU_PD(int N, double** b)
xue@1 1495 {
xue@1 1496 if (b[0][0]==0) return 1;
xue@1 1497 for (int j=1; j<3; j++) b[j][0]=b[j][0]/b[0][0];
xue@1 1498 for (int i=1; i<N-1; i++)
xue@1 1499 {
xue@1 1500 for (int k=i-2; k<i; k++) b[0][i]-=b[i-k][k]*b[k-i][i];
xue@1 1501 if (b[0][i]==0) return 2;
xue@1 1502 for (int j=i+1; j<i+3; j++)
xue@1 1503 {
xue@1 1504 for (int k=j-2; k<i; k++) b[i-j][j]-=b[i-k][k]*b[k-j][j];
xue@1 1505 for (int k=j-2; k<i; k++) b[j-i][i]-=b[j-k][k]*b[k-i][i];
xue@1 1506 b[j-i][i]/=b[0][i];
xue@1 1507 }
xue@1 1508 }
xue@1 1509 for (int k=N-3; k<N-1; k++) b[0][N-1]-=b[N-1-k][k]*b[k-N+1][N-1];
xue@1 1510 return 0;
xue@1 1511 }//LU_PD*/
xue@1 1512
xue@1 1513 /*
xue@1 1514 function LU_PD: solve pentadiagonal system Ax=c
xue@1 1515
xue@1 1516 In: pentadiagonal matrix A[N][N] stored in a compact format in b[-2:2][N], vector c[N]
xue@1 1517 Out: vector c now containing x.
xue@1 1518
xue@1 1519 Returns 0 if successful. On return b is in the LU form.
xue@1 1520 */
xue@1 1521 int LU_PD(int N, double** b, double* c)
xue@1 1522 {
xue@1 1523 int result=LU_PD(N, b);
xue@1 1524 if (result==0)
xue@1 1525 {
xue@1 1526 //L loop
xue@1 1527 c[1]=c[1]-b[1][0]*c[0];
xue@1 1528 for (int i=2; i<N; i++)
xue@1 1529 c[i]=c[i]-b[1][i-1]*c[i-1]-b[2][i-2]*c[i-2];
xue@1 1530 //U loop
xue@1 1531 c[N-1]/=b[0][N-1];
xue@1 1532 c[N-2]=(c[N-2]-b[-1][N-1]*c[N-1])/b[0][N-2];
xue@1 1533 for (int i=N-3; i>=0; i--)
xue@1 1534 c[i]=(c[i]-b[-1][i+1]*c[i+1]-b[-2][i+2]*c[i+2])/b[0][i];
xue@1 1535 }
xue@1 1536 return result;
xue@1 1537 }//LU_PD
xue@1 1538
xue@1 1539 //---------------------------------------------------------------------------
xue@1 1540 /*
xue@1 1541 function LUCP: LU decomposition A=LU with column pivoting
xue@1 1542
xue@1 1543 In: matrix A[N][N]
xue@1 1544 Out: matrix A[N][N] now holding L and U by L_U[i][j]=A[ind[i]][j], where L_U
xue@1 1545 hosts L and U according to mode:
xue@1 1546 mode=0: L diag=abs(U diag), U diag as return
xue@1 1547 mode=1: L diag=1, U diag as return
xue@1 1548 mode=2: U diag=1, L diag as return
xue@1 1549
xue@1 1550 Returns the determinant of A.
xue@1 1551 */
xue@1 1552 double LUCP(double **A, int N, int *ind, int &parity, int mode)
xue@1 1553 {
xue@1 1554 double det=1;
xue@1 1555 parity=1;
xue@1 1556
xue@1 1557 for (int i=0; i<N; i++) ind[i]=i;
xue@1 1558 double vmax, *norm=new double[N]; //norm[n] is the maxima of row n
xue@1 1559 for (int i=0; i<N; i++)
xue@1 1560 {
xue@1 1561 vmax=fabs(A[i][0]);
xue@1 1562 double tmp;
xue@1 1563 for (int j=1; j<N; j++) if ((tmp=fabs(A[i][j]))>vmax) vmax=tmp;
xue@1 1564 if (vmax==0) { parity=0; goto deletenorm; } //det=0 at this point
xue@1 1565 norm[i]=1/vmax;
xue@1 1566 }
xue@1 1567
xue@1 1568 int maxind;
xue@1 1569 for (int j=0; j<N; j++)
xue@1 1570 { //Column j
xue@1 1571 for (int i=0; i<j; i++)
xue@1 1572 {
xue@1 1573 //row i, i<j
xue@1 1574 double tmp=A[i][j];
xue@1 1575 for (int k=0; k<i; k++) tmp-=A[i][k]*A[k][j];
xue@1 1576 A[i][j]=tmp;
xue@1 1577 }
xue@1 1578 for (int i=j; i<N; i++)
xue@1 1579 {
xue@1 1580 //row i, i>=j
xue@1 1581 double tmp=A[i][j]; for (int k=0; k<j; k++) tmp-=A[i][k]*A[k][j]; A[i][j]=tmp;
xue@1 1582 double tmp2=norm[i]*fabs(tmp);
xue@1 1583 if (i==j || tmp2>=vmax) maxind=i, vmax=tmp2;
xue@1 1584 }
xue@1 1585 if (vmax==0) { parity=0; goto deletenorm; } //pivot being zero
xue@1 1586 if (j!=maxind)
xue@1 1587 {
xue@1 1588 //do column pivoting: switching rows
xue@1 1589 for (int k=0; k<N; k++) { double tmp=A[maxind][k]; A[maxind][k]=A[j][k]; A[j][k]=tmp; }
xue@1 1590 parity=-parity;
xue@1 1591 norm[maxind]=norm[j];
xue@1 1592 }
xue@1 1593 int itmp=ind[j]; ind[j]=ind[maxind]; ind[maxind]=itmp;
xue@1 1594 if (j!=N-1)
xue@1 1595 {
xue@1 1596 double den=1/A[j][j];
xue@1 1597 for (int i=j+1; i<N; i++) A[i][j]*=den;
xue@1 1598 }
xue@1 1599 det*=A[j][j];
xue@1 1600 } //Go back for the next column in the reduction.
xue@1 1601
xue@1 1602 if (mode==0)
xue@1 1603 {
xue@1 1604 for (int i=0; i<N-1; i++)
xue@1 1605 {
xue@1 1606 double den=sqrt(fabs(A[i][i]));
xue@1 1607 double iden=1/den;
xue@1 1608 for (int j=i+1; j<N; j++) A[j][i]*=den, A[i][j]*=iden;
xue@1 1609 A[i][i]*=iden;
xue@1 1610 }
xue@1 1611 A[N-1][N-1]/=sqrt(fabs(A[N-1][N-1]));
xue@1 1612 }
xue@1 1613 else if (mode==2)
xue@1 1614 {
xue@1 1615 for (int i=0; i<N-1; i++)
xue@1 1616 {
xue@1 1617 double den=A[i][i];
xue@1 1618 double iden=1/den;
xue@1 1619 for (int j=i+1; j<N; j++) A[j][i]*=den, A[i][j]*=iden;
xue@1 1620 }
xue@1 1621 }
xue@1 1622
xue@1 1623 deletenorm:
xue@1 1624 delete[] norm;
xue@1 1625 return det*parity;
xue@1 1626 }//LUCP
xue@1 1627
xue@1 1628 //---------------------------------------------------------------------------
xue@1 1629 /*
xue@1 1630 function maxind: returns the index of the maximal value of data[from:(to-1)].
xue@1 1631
xue@1 1632 In: vector data containing at least $to entries.
xue@1 1633 Out: the index to the maximal entry of data[from:(to-1)]
xue@1 1634
xue@1 1635 Returns the index to the maximal value.
xue@1 1636 */
xue@1 1637 int maxind(double* data, int from, int to)
xue@1 1638 {
xue@1 1639 int result=from;
xue@1 1640 for (int i=from+1; i<to; i++) if (data[result]<data[i]) result=i;
xue@1 1641 return result;
xue@1 1642 }//maxind
xue@1 1643
xue@1 1644 //---------------------------------------------------------------------------
xue@1 1645 /*
xue@1 1646 macro Multiply_vect: matrix-vector multiplications
xue@1 1647
xue@1 1648 Each expansion of this macro implements two functions named $MULTIPLY that do matrix-vector
xue@1 1649 multiplication. Functions are named after their exact functions. For example, MultiplyXty() does
xue@1 1650 multiplication of the transpose of matrix X with vector y, where postfix "t" attched to Y stands for
xue@1 1651 transpose. Likewise, the postfix "c" stands for conjugate, and "h" stnads for Hermitian (conjugate
xue@1 1652 transpose).
xue@1 1653
xue@1 1654 Two dimension arguments are needed by each function. The first of the two is the number of entries to
xue@1 1655 the output vector; the second of the two is the "other" dimension of the matrix multiplier.
xue@1 1656 */
xue@1 1657 #define Multiply_vect(MULTIPLY, DbZ, DbX, DbY, xx, yy) \
xue@1 1658 DbZ* MULTIPLY(int M, int N, DbZ* z, DbX* x, DbY* y, MList* List) \
xue@1 1659 { \
xue@1 1660 if (!z){z=new DbZ[M]; if (List) List->Add(z, 1);} \
xue@1 1661 for (int m=0; m<M; m++){z[m]=0; for (int n=0; n<N; n++) z[m]+=xx*yy;} \
xue@1 1662 return z; \
xue@1 1663 } \
xue@1 1664 DbZ* MULTIPLY(int M, int N, DbX* x, DbY* y, MList* List) \
xue@1 1665 { \
xue@1 1666 DbZ* z=new DbZ[M]; if (List) List->Add(z, 1); \
xue@1 1667 for (int m=0; m<M; m++){z[m]=0; for (int n=0; n<N; n++) z[m]+=xx*yy;} \
xue@1 1668 return z; \
xue@1 1669 }
xue@1 1670 //function MultiplyXy: z[M]=x[M][N]y[N], identical z and y NOT ALLOWED
xue@1 1671 Multiply_vect(MultiplyXy, double, double*, double, x[m][n], y[n])
xue@1 1672 Multiply_vect(MultiplyXy, cdouble, cdouble*, cdouble, x[m][n], y[n])
xue@1 1673 Multiply_vect(MultiplyXy, cdouble, double*, cdouble, x[m][n], y[n])
xue@1 1674 //function MultiplyxY: z[M]=x[N]y[N][M], identical z and x NOT ALLOWED
xue@1 1675 Multiply_vect(MultiplyxY, double, double, double*, x[n], y[n][m])
xue@1 1676 Multiply_vect(MultiplyxY, cdouble, cdouble, cdouble*, x[n], y[n][m])
xue@1 1677 //function MultiplyXty: z[M]=xt[M][N]y[N]
xue@1 1678 Multiply_vect(MultiplyXty, double, double*, double, x[n][m], y[n])
xue@1 1679 Multiply_vect(MultiplyXty, cdouble, cdouble*, cdouble, x[n][m], y[n])
xue@1 1680 //function MultiplyXhy: z[M]=xh[M][N]y[N]
xue@1 1681 Multiply_vect(MultiplyXhy, cdouble, cdouble*, cdouble, *x[n][m], y[n])
xue@1 1682 //function MultiplyxYt: z[M]=x[N]yt[N][M]
xue@1 1683 Multiply_vect(MultiplyxYt, double, double, double*, x[n], y[m][n])
xue@1 1684 //function MultiplyXcy: z[M]=(x*)[M][N]y[N]
xue@1 1685 Multiply_vect(MultiplyXcy, cdouble, cdouble*, cdouble, *x[m][n], y[n])
xue@1 1686 Multiply_vect(MultiplyXcy, cdouble, cdouble*, cfloat, *x[m][n], y[n])
xue@1 1687
xue@1 1688 //---------------------------------------------------------------------------
xue@1 1689 /*
xue@1 1690 function Norm1: L-1 norm of a square matrix A
xue@1 1691
xue@1 1692 In: matrix A[N][N]
xue@1 1693 Out: its L-1 norm
xue@1 1694
xue@1 1695 Returns the L-1 norm.
xue@1 1696 */
xue@1 1697 double Norm1(int N, double** A)
xue@1 1698 {
xue@1 1699 double result=0, norm;
xue@1 1700 for (int i=0; i<N; i++)
xue@1 1701 {
xue@1 1702 norm=0; for (int j=0; j<N; j++) norm+=fabs(A[i][j]);
xue@1 1703 if (result<norm) result=norm;
xue@1 1704 }
xue@1 1705 return result;
xue@1 1706 }//Norm1
xue@1 1707
xue@1 1708 //---------------------------------------------------------------------------
xue@1 1709 /*
xue@1 1710 function QL: QL method for solving tridiagonal symmetric matrix eigenvalue problem.
xue@1 1711
xue@1 1712 In: A[N][N]: tridiagonal symmetric matrix stored in d[N] and sd[] arranged so that d[0:n-1] contains
xue@1 1713 the diagonal elements of A, sd[0]=0, sd[1:n-1] contains the subdiagonal elements of A.
xue@1 1714 z[N][N]: pre-transform matrix z[N][N] compatible with HouseHolder() routine.
xue@1 1715 Out: d[N]: the eigenvalues of A
xue@1 1716 z[N][N] the eigenvectors of A.
xue@1 1717
xue@1 1718 Returns 0 if successful. sd[] should have storage for at least N+1 entries.
xue@1 1719 */
xue@1 1720 int QL(int N, double* d, double* sd, double** z)
xue@1 1721 {
xue@1 1722 const int maxiter=30;
xue@1 1723 for (int i=1; i<N; i++) sd[i-1]=sd[i];
xue@1 1724 sd[N]=0.0;
xue@1 1725 for (int l=0; l<N; l++)
xue@1 1726 {
xue@1 1727 int iter=0, m;
xue@1 1728 do
xue@1 1729 {
xue@1 1730 for (m=l; m<N-1; m++)
xue@1 1731 {
xue@1 1732 double dd=fabs(d[m])+fabs(d[m+1]);
xue@1 1733 if (fabs(sd[m])+dd==dd) break;
xue@1 1734 }
xue@1 1735 if (m!=l)
xue@1 1736 {
xue@1 1737 iter++;
xue@1 1738 if (iter>=maxiter) return 1;
xue@1 1739 double g=(d[l+1]-d[l])/(2*sd[l]);
xue@1 1740 double r=sqrt(g*g+1);
xue@1 1741 g=d[m]-d[l]+sd[l]/(g+(g>=0?r:-r));
xue@1 1742 double s=1, c=1, p=0;
xue@1 1743 int i;
xue@1 1744 for (i=m-1; i>=l; i--)
xue@1 1745 {
xue@1 1746 double f=s*sd[i], b=c*sd[i];
xue@1 1747 sd[i+1]=(r=sqrt(f*f+g*g));
xue@1 1748 if (r==0)
xue@1 1749 {
xue@1 1750 d[i+1]-=p;
xue@1 1751 sd[m]=0;
xue@1 1752 break;
xue@1 1753 }
xue@1 1754 s=f/r, c=g/r;
xue@1 1755 g=d[i+1]-p;
xue@1 1756 r=(d[i]-g)*s+2.0*c*b;
xue@1 1757 p=s*r;
xue@1 1758 d[i+1]=g+p;
xue@1 1759 g=c*r-b;
xue@1 1760 for (int k=0; k<N; k++)
xue@1 1761 {
xue@1 1762 f=z[k][i+1];
xue@1 1763 z[k][i+1]=s*z[k][i]+c*f;
xue@1 1764 z[k][i]=c*z[k][i]-s*f;
xue@1 1765 }
xue@1 1766 }
xue@1 1767 if (r==0 && i>=l) continue;
xue@1 1768 d[l]-=p;
xue@1 1769 sd[l]=g;
xue@1 1770 sd[m]=0.0;
xue@1 1771 }
xue@1 1772 }
xue@1 1773 while (m!=l);
xue@1 1774 }
xue@1 1775 return 0;
xue@1 1776 }//QL
xue@1 1777
xue@1 1778 //---------------------------------------------------------------------------
xue@1 1779 /*
xue@1 1780 function QR: nr version of QR method for solving upper Hessenberg system A. This is compatible with
xue@1 1781 Hessenb method.
xue@1 1782
xue@1 1783 In: matrix A[N][N]
xue@1 1784 Out: vector ev[N] of eigenvalues
xue@1 1785
xue@1 1786 Returns 0 on success. Content of matrix A is destroyed on return.
xue@1 1787 */
xue@1 1788 int QR(int N, double **A, cdouble* ev)
xue@1 1789 {
xue@1 1790 int n=N, m, l, k, j, iter, i, mmin, maxiter=30;
xue@1 1791 double **a=A, z, y, x, w, v, u, t=0, s, r, q, p, a1=0;
xue@1 1792 for (i=0; i<n; i++) for (j=i-1>0?i-1:0; j<n; j++) a1+=fabs(a[i][j]);
xue@1 1793 n--;
xue@1 1794 while (n>=0)
xue@1 1795 {
xue@1 1796 iter=0;
xue@1 1797 do
xue@1 1798 {
xue@1 1799 for (l=n; l>0; l--)
xue@1 1800 {
xue@1 1801 s=fabs(a[l-1][l-1])+fabs(a[l][l]);
xue@1 1802 if (s==0) s=a1;
xue@1 1803 if (fabs(a[l][l-1])+s==s) {a[l][l-1]=0; break;}
xue@1 1804 }
xue@1 1805 x=a[n][n];
xue@1 1806 if (l==n) {ev[n].x=x+t; ev[n--].y=0;}
xue@1 1807 else
xue@1 1808 {
xue@1 1809 y=a[n-1][n-1], w=a[n][n-1]*a[n-1][n];
xue@1 1810 if (l==(n-1))
xue@1 1811 {
xue@1 1812 p=0.5*(y-x);
xue@1 1813 q=p*p+w;
xue@1 1814 z=sqrt(fabs(q));
xue@1 1815 x+=t;
xue@1 1816 if (q>=0)
xue@1 1817 {
xue@1 1818 z=p+(p>=0?z:-z);
xue@1 1819 ev[n-1].x=ev[n].x=x+z;
xue@1 1820 if (z) ev[n].x=x-w/z;
xue@1 1821 ev[n-1].y=ev[n].y=0;
xue@1 1822 }
xue@1 1823 else
xue@1 1824 {
xue@1 1825 ev[n-1].x=ev[n].x=x+p;
xue@1 1826 ev[n].y=z; ev[n-1].y=-z;
xue@1 1827 }
xue@1 1828 n-=2;
xue@1 1829 }
xue@1 1830 else
xue@1 1831 {
xue@1 1832 if (iter>=maxiter) return 1;
xue@1 1833 if (iter%10==9)
xue@1 1834 {
xue@1 1835 t+=x;
xue@1 1836 for (i=0; i<=n; i++) a[i][i]-=x;
xue@1 1837 s=fabs(a[n][n-1])+fabs(a[n-1][n-2]);
xue@1 1838 y=x=0.75*s;
xue@1 1839 w=-0.4375*s*s;
xue@1 1840 }
xue@1 1841 iter++;
xue@1 1842 for (m=n-2; m>=l; m--)
xue@1 1843 {
xue@1 1844 z=a[m][m];
xue@1 1845 r=x-z; s=y-z;
xue@1 1846 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];
xue@1 1847 s=fabs(p)+fabs(q)+fabs(r);
xue@1 1848 p/=s; q/=s; r/=s;
xue@1 1849 if (m==l) break;
xue@1 1850 u=fabs(a[m][m-1])*(fabs(q)+fabs(r));
xue@1 1851 v=fabs(p)*(fabs(a[m-1][m-1])+fabs(z)+fabs(a[m+1][m+1]));
xue@1 1852 if (u+v==v) break;
xue@1 1853 }
xue@1 1854 for (i=m+2; i<=n; i++)
xue@1 1855 {
xue@1 1856 a[i][i-2]=0;
xue@1 1857 if (i!=m+2) a[i][i-3]=0;
xue@1 1858 }
xue@1 1859 for (k=m; k<=n-1; k++)
xue@1 1860 {
xue@1 1861 if (k!=m)
xue@1 1862 {
xue@1 1863 p=a[k][k-1];
xue@1 1864 q=a[k+1][k-1];
xue@1 1865 r=0;
xue@1 1866 if (k!=n-1) r=a[k+2][k-1];
xue@1 1867 x=fabs(p)+fabs(q)+fabs(r);
xue@1 1868 if (x!=0) p/=x, q/=x, r/=x;
xue@1 1869 }
xue@1 1870 if (p>=0) s=sqrt(p*p+q*q+r*r);
xue@1 1871 else s=-sqrt(p*p+q*q+r*r);
xue@1 1872 if (s!=0)
xue@1 1873 {
xue@1 1874 if (k==m)
xue@1 1875 {
xue@1 1876 if (l!=m) a[k][k-1]=-a[k][k-1];
xue@1 1877 }
xue@1 1878 else a[k][k-1]=-s*x;
xue@1 1879 p+=s;
xue@1 1880 x=p/s; y=q/s; z=r/s; q/=p; r/=p;
xue@1 1881 for (j=k; j<=n; j++)
xue@1 1882 {
xue@1 1883 p=a[k][j]+q*a[k+1][j];
xue@1 1884 if (k!=n-1)
xue@1 1885 {
xue@1 1886 p+=r*a[k+2][j];
xue@1 1887 a[k+2][j]-=p*z;
xue@1 1888 }
xue@1 1889 a[k+1][j]-=p*y; a[k][j]-=p*x;
xue@1 1890 }
xue@1 1891 mmin=n<k+3?n:k+3;
xue@1 1892 for (i=l; i<=mmin; i++)
xue@1 1893 {
xue@1 1894 p=x*a[i][k]+y*a[i][k+1];
xue@1 1895 if (k!=(n-1))
xue@1 1896 {
xue@1 1897 p+=z*a[i][k+2];
xue@1 1898 a[i][k+2]-=p*r;
xue@1 1899 }
xue@1 1900 a[i][k+1]-=p*q; a[i][k]-=p;
xue@1 1901 }
xue@1 1902 }
xue@1 1903 }
xue@1 1904 }
xue@1 1905 }
xue@1 1906 } while (n>l+1);
xue@1 1907 }
xue@1 1908 return 0;
xue@1 1909 }//QR
xue@1 1910
xue@1 1911 /*
xue@1 1912 function QR_GS: QR decomposition A=QR using Gram-Schmidt method
xue@1 1913
xue@1 1914 In: matrix A[M][N], M>=N
xue@1 1915 Out: Q[M][N], R[N][N]
xue@1 1916
xue@1 1917 No return value.
xue@1 1918 */
xue@1 1919 void QR_GS(int M, int N, double** A, double** Q, double** R)
xue@1 1920 {
xue@1 1921 double *u=new double[M];
xue@1 1922 for (int n=0; n<N; n++)
xue@1 1923 {
xue@1 1924 memset(R[n], 0, sizeof(double)*N);
xue@1 1925 for (int m=0; m<M; m++) u[m]=A[m][n];
xue@1 1926 for (int k=0; k<n; k++)
xue@1 1927 {
xue@1 1928 double ip=0; for (int m=0; m<M; m++) ip+=u[m]*Q[m][k];
xue@1 1929 for (int m=0; m<M; m++) u[m]-=ip*Q[m][k];
xue@1 1930 R[k][n]=ip;
xue@1 1931 }
xue@1 1932 double iu=0; for (int m=0; m<M; m++) iu+=u[m]*u[m]; iu=sqrt(iu);
xue@1 1933 R[n][n]=iu;
xue@1 1934 iu=1.0/iu; for (int m=0; m<M; m++) Q[m][n]=u[m]*iu;
xue@1 1935 }
xue@1 1936 delete[] u;
xue@1 1937 }//QR_GS
xue@1 1938
xue@1 1939 /*
xue@1 1940 function QR_householder: QR decomposition using householder transform
xue@1 1941
xue@1 1942 In: A[M][N], M>=N
xue@1 1943 Out: Q[M][M], R[M][N]
xue@1 1944
xue@1 1945 No return value.
xue@1 1946 */
xue@1 1947 void QR_householder(int M, int N, double** A, double** Q, double** R)
xue@1 1948 {
xue@1 1949 double *u=new double[M*3], *ur=&u[M], *qu=&u[M*2];
xue@1 1950 for (int m=0; m<M; m++)
xue@1 1951 {
xue@1 1952 memcpy(R[m], A[m], sizeof(double)*N);
xue@1 1953 memset(Q[m], 0, sizeof(double)*M); Q[m][m]=1;
xue@1 1954 }
xue@1 1955 for (int n=0; n<N; n++)
xue@1 1956 {
xue@1 1957 double alf=0; for (int m=n; m<M; m++) alf+=R[m][n]*R[m][n]; alf=sqrt(alf);
xue@1 1958 if (R[n][n]>0) alf=-alf;
xue@1 1959 for (int m=n; m<M; m++) u[m]=R[m][n]; u[n]=u[n]-alf;
xue@1 1960 double iu2=0; for (int m=n; m<M; m++) iu2+=u[m]*u[m]; iu2=2.0/iu2;
xue@1 1961 for (int m=n; m<N; m++)
xue@1 1962 {
xue@1 1963 ur[m]=0; for (int k=n; k<M; k++) ur[m]+=u[k]*R[k][m];
xue@1 1964 }
xue@1 1965 for (int m=0; m<M; m++)
xue@1 1966 {
xue@1 1967 qu[m]=0; for (int k=n; k<M; k++) qu[m]+=Q[m][k]*u[k];
xue@1 1968 }
xue@1 1969 for (int m=n; m<M; m++) u[m]=u[m]*iu2;
xue@1 1970 for (int m=n; m<M; m++) for (int k=n; k<N; k++) R[m][k]-=u[m]*ur[k];
xue@1 1971 for (int m=0; m<M; m++) for (int k=n; k<M; k++) Q[m][k]-=qu[m]*u[k];
xue@1 1972 }
xue@1 1973 delete[] u;
xue@1 1974 }//QR_householder
xue@1 1975
xue@1 1976 //---------------------------------------------------------------------------
xue@1 1977 /*
xue@1 1978 function QU: Unitary decomposition A=QU, where Q is unitary and U is upper triangular
xue@1 1979
xue@1 1980 In: matrix A[N][N]
xue@1 1981 Out: matrices Q[N][N], A[n][n] now containing U
xue@1 1982
xue@1 1983 No return value.
xue@1 1984 */
xue@1 1985 void QU(int N, double** Q, double** A)
xue@1 1986 {
xue@1 1987 int sizeN=sizeof(double)*N;
xue@1 1988 for (int i=0; i<N; i++) {memset(Q[i], 0, sizeN); Q[i][i]=1;}
xue@1 1989
xue@1 1990 double m, s, c, *tmpi=new double[N], *tmpj=new double[N];
xue@1 1991 for (int i=1; i<N; i++) for (int j=0; j<i; j++)
xue@1 1992 if (A[i][j]!=0)
xue@1 1993 {
xue@1 1994 m=sqrt(A[j][j]*A[j][j]+A[i][j]*A[i][j]);
xue@1 1995 s=A[i][j]/m;
xue@1 1996 c=A[j][j]/m;
xue@1 1997 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];
xue@1 1998 memcpy(A[i], tmpi, sizeN), memcpy(A[j], tmpj, sizeN);
xue@1 1999 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];
xue@1 2000 memcpy(Q[i], tmpi, sizeN), memcpy(Q[j], tmpj, sizeN);
xue@1 2001 }
xue@1 2002 delete[] tmpi; delete[] tmpj;
xue@1 2003 transpose(N, Q);
xue@1 2004 }//QU
xue@1 2005
xue@1 2006 //---------------------------------------------------------------------------
xue@1 2007 /*
xue@1 2008 function Real: extracts the real part of matrix X
xue@1 2009
xue@1 2010 In: matrix x[M][N];
xue@1 2011 Out: matrix z[M][N]
xue@1 2012
xue@1 2013 Returns pointer to z. z is created anew if z=0 is specified on start.
xue@1 2014 */
xue@1 2015 double** Real(int M, int N, double** z, cdouble** x, MList* List)
xue@1 2016 {
xue@1 2017 if (!z){Allocate2(double, M, N, z); if (List) List->Add(z, 2);}
xue@1 2018 for (int m=0; m<M; m++) for (int n=0; n<N; n++) z[m][n]=x[m][n].x;
xue@1 2019 return z;
xue@1 2020 }//Real
xue@1 2021 double** Real(int M, int N, cdouble** x, MList* List){return Real(M, N, 0, x, List);}
xue@1 2022
xue@1 2023 //---------------------------------------------------------------------------
xue@1 2024 /*
xue@1 2025 function Roots: finds the roots of a polynomial. x^N+p[N-1]x^(N-1)+p[N-2]x^(N-2)...+p[0]
xue@1 2026
xue@1 2027 In: vector p[N] of polynomial coefficients.
xue@1 2028 Out: vector r[N] of roots.
xue@1 2029
xue@1 2030 Returns 0 if successful.
xue@1 2031 */
xue@1 2032 int Roots(int N, double* p, cdouble* r)
xue@1 2033 {
xue@1 2034 double** A=new double*[N]; A[0]=new double[N*N]; for (int i=1; i<N; i++) A[i]=&A[0][i*N];
xue@1 2035 for (int i=0; i<N; i++) A[0][i]=-p[N-1-i];
xue@1 2036 if (N>1) memset(A[1], 0, sizeof(double)*N*(N-1));
xue@1 2037 for (int i=1; i<N; i++) A[i][i-1]=1;
xue@1 2038 BalanceSim(N, A);
xue@1 2039 double result=QR(N, A, r);
xue@1 2040 delete[] A[0]; delete[] A;
xue@1 2041 return result;
xue@1 2042 }//Roots
xue@1 2043 //real implementation
xue@1 2044 int Roots(int N, double* p, double* rr, double* ri)
xue@1 2045 {
xue@1 2046 cdouble* r=new cdouble[N];
xue@1 2047 int result=Roots(N, p, r);
xue@1 2048 for (int n=0; n<N; n++) rr[n]=r[n].x, ri[n]=r[n].y;
xue@1 2049 delete[] r;
xue@1 2050 return result;
xue@1 2051 }//Roots
xue@1 2052
xue@1 2053 //---------------------------------------------------------------------------
xue@1 2054 /*
xue@1 2055 function SorI: Sor iteration algorithm for solving linear system Ax=b.
xue@1 2056
xue@1 2057 Sor method is an extension of the Gaussian-Siedel method, with the latter equivalent to the former
xue@1 2058 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
xue@1 2059 is diagonal, L is lower triangular, U is upper triangular and A=L+D+U. Sor method converges if A is
xue@1 2060 positive definite.
xue@1 2061
xue@1 2062 In: matrix A[N][N], vector b[N], initial vector x0[N]
xue@1 2063 Out: vector x0[N]
xue@1 2064
xue@1 2065 Returns 0 if successful. Contents of matrix A and vector b are unchanged on return.
xue@1 2066 */
xue@1 2067 int SorI(int N, double* x0, double** a, double* b, double w, double ep, int maxiter)
xue@1 2068 {
xue@1 2069 double e, v=1-w, *x=new double[N];
xue@1 2070 int k=0, sizeN=sizeof(double)*N;
xue@1 2071 while (k<maxiter)
xue@1 2072 {
xue@1 2073 for (int i=0; i<N; i++)
xue@1 2074 {
xue@1 2075 x[i]=b[i];
xue@1 2076 for (int j=0; j<i; j++) x[i]-=a[i][j]*x[j];
xue@1 2077 for (int j=i+1; j<N; j++) x[i]-=a[i][j]*x0[j];
xue@1 2078 x[i]=v*x0[i]+w*x[i]/a[i][i];
xue@1 2079 }
xue@1 2080 e=0; for (int j=0; j<N; j++) e+=fabs(x[j]-x0[j]);
xue@1 2081 memcpy(x0, x, sizeN);
xue@1 2082 if (e<ep) break;
xue@1 2083 k++;
xue@1 2084 }
xue@1 2085 delete[] x;
xue@1 2086 if (k>=maxiter) return 1;
xue@1 2087 return 0;
xue@1 2088 }//SorI
xue@1 2089
xue@1 2090 //---------------------------------------------------------------------------
xue@1 2091 //Submatrix routines
xue@1 2092
xue@1 2093 /*
xue@1 2094 function SetSubMatrix: copy matrix x[Y][X] into matrix z at (Y1, X1).
xue@1 2095
xue@1 2096 In: matrix x[Y][X], matrix z with dimensions no less than [Y+Y1][X+X1]
xue@1 2097 Out: matrix z, updated.
xue@1 2098
xue@1 2099 No return value.
xue@1 2100 */
xue@1 2101 void SetSubMatrix(double** z, double** x, int Y1, int Y, int X1, int X)
xue@1 2102 {
xue@1 2103 for (int y=0; y<Y; y++) memcpy(&z[Y1+y][X1], x[y], sizeof(double)*X);
xue@1 2104 }//SetSubMatrix
xue@1 2105 //complex version
xue@1 2106 void SetSubMatrix(cdouble** z, cdouble** x, int Y1, int Y, int X1, int X)
xue@1 2107 {
xue@1 2108 for (int y=0; y<Y; y++) memcpy(&z[Y1+y][X1], x[y], sizeof(cdouble)*X);
xue@1 2109 }//SetSubMatrix
xue@1 2110
xue@1 2111 /*
xue@1 2112 function SubMatrix: extract a submatrix of x at (Y1, X1) to z[Y][X].
xue@1 2113
xue@1 2114 In: matrix x of dimensions no less than [Y+Y1][X+X1]
xue@1 2115 Out: matrix z[Y][X].
xue@1 2116
xue@1 2117 Returns pointer to z. z is created anew if z=0 is specifid on start.
xue@1 2118 */
xue@1 2119 cdouble** SubMatrix(cdouble** z, cdouble** x, int Y1, int Y, int X1, int X, MList* List)
xue@1 2120 {
xue@1 2121 if (!z) {Allocate2(cdouble, Y, X, z); if (List) List->Add(z, 2);}
xue@1 2122 for (int y=0; y<Y; y++) memcpy(z[y], &x[Y1+y][X1], sizeof(cdouble)*X);
xue@1 2123 return z;
xue@1 2124 }//SetSubMatrix
xue@1 2125 //wrapper function
xue@1 2126 cdouble** SubMatrix(cdouble** x, int Y1, int Y, int X1, int X, MList* List)
xue@1 2127 {
xue@1 2128 return SubMatrix(0, x, Y1, Y, X1, X, List);
xue@1 2129 }//SetSubMatrix
xue@1 2130
xue@1 2131 /*
xue@1 2132 function SubVector: extract a subvector of x at X1 to z[X].
xue@1 2133
xue@1 2134 In: vector x no shorter than X+X1.
xue@1 2135 Out: vector z[X].
xue@1 2136
xue@1 2137 Returns pointer to z. z is created anew if z=0 is specifid on start.
xue@1 2138 */
xue@1 2139 cdouble* SubVector(cdouble* z, cdouble* x, int X1, int X, MList* List)
xue@1 2140 {
xue@1 2141 if (!z){z=new cdouble[X]; if (List) List->Add(z, 1);}
xue@1 2142 memcpy(z, &x[X1], sizeof(cdouble)*X);
xue@1 2143 return z;
xue@1 2144 }//SubVector
xue@1 2145 //wrapper function
xue@1 2146 cdouble* SubVector(cdouble* x, int X1, int X, MList* List)
xue@1 2147 {
xue@1 2148 return SubVector(0, x, X1, X, List);
xue@1 2149 }//SubVector
xue@1 2150
xue@1 2151 //---------------------------------------------------------------------------
xue@1 2152 /*
xue@1 2153 function transpose: matrix transpose: A'->A
xue@1 2154
xue@1 2155 In: matrix a[N][N]
xue@1 2156 Out: matrix a[N][N] after transpose
xue@1 2157
xue@1 2158 No return value.
xue@1 2159 */
xue@1 2160 void transpose(int N, double** a)
xue@1 2161 {
xue@1 2162 double tmp;
xue@1 2163 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;}
xue@1 2164 }//transpose
xue@1 2165 //complex version
xue@1 2166 void transpose(int N, cdouble** a)
xue@1 2167 {
xue@1 2168 cdouble tmp;
xue@1 2169 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;}
xue@1 2170 }//transpose
xue@1 2171
xue@1 2172 /*
xue@1 2173 function transpose: matrix transpose: A'->Z
xue@1 2174
xue@1 2175 In: matrix a[M][N]
xue@1 2176 Out: matrix z[N][M]
xue@1 2177
xue@1 2178 Returns pointer to z. z is created anew if z=0 is specifid on start.
xue@1 2179 */
xue@1 2180 double** transpose(int N, int M, double** ta, double** a, MList* List)
xue@1 2181 {
xue@1 2182 if (!ta) {Allocate2(double, N, M, ta); if (List) List->Add(ta, 2);}
xue@1 2183 for (int n=0; n<N; n++) for (int m=0; m<M; m++) ta[n][m]=a[m][n];
xue@1 2184 return ta;
xue@1 2185 }//transpose
xue@1 2186 //wrapper function
xue@1 2187 double** transpose(int N, int M, double** a, MList* List)
xue@1 2188 {
xue@1 2189 return transpose(N, M, 0, a, List);
xue@1 2190 }//transpose
xue@1 2191
xue@1 2192 //---------------------------------------------------------------------------
xue@1 2193 /*
xue@1 2194 function Unitary: given x & y s.t. |x|=|y|, find unitary matrix P s.t. Px=y. P is given in closed form
xue@1 2195 as I-(x-y)(x-y)'/(x-y)'x
xue@1 2196
xue@1 2197 In: vectors x[N] and y[N]
xue@1 2198 Out: matrix P[N][N]
xue@1 2199
xue@1 2200 Returns pointer to P. P is created anew if P=0 is specified on start.
xue@1 2201 */
xue@1 2202 double** Unitary(int N, double** P, double* x, double* y, MList* List)
xue@1 2203 {
xue@1 2204 if (!P) {Allocate2(double, N, N, P); if (List) List->Add(P, 2);}
xue@1 2205 int sizeN=sizeof(double)*N;
xue@1 2206 for (int i=0; i<N; i++) {memset(P[i], 0, sizeN); P[i][i]=1;}
xue@1 2207
xue@1 2208 double* w=MultiAdd(N, x, y, -1.0); //w=x-y
xue@1 2209 double m=Inner(N, x, w); //m=(x-y)'x
xue@1 2210 if (m!=0)
xue@1 2211 {
xue@1 2212 m=1.0/m; //m=1/(x-y)'x
xue@1 2213 double* mw=Multiply(N, w, m);
xue@1 2214 for (int i=0; i<N; i++) for (int j=0; j<N; j++) P[i][j]=P[i][j]-mw[i]*w[j];
xue@1 2215 delete[] mw;
xue@1 2216 }
xue@1 2217 delete[] w;
xue@1 2218 return P;
xue@1 2219 }//Unitary
xue@1 2220 //complex version
xue@1 2221 cdouble** Unitary(int N, cdouble** P, cdouble* x, cdouble* y, MList* List)
xue@1 2222 {
xue@1 2223 if (!P) {Allocate2(cdouble, N, N, P);}
xue@1 2224 int sizeN=sizeof(cdouble)*N;
xue@1 2225 for (int i=0; i<N; i++) {memset(P[i], 0, sizeN); P[i][i]=1;}
xue@1 2226
xue@1 2227 cdouble *w=MultiAdd(N, x, y, -1);
xue@1 2228 cdouble m=Inner(N, x, w);
xue@1 2229 if (m!=0)
xue@1 2230 {
xue@1 2231 m=m.cinv();
xue@1 2232 cdouble *mw=Multiply(N, w, m);
xue@1 2233 for (int i=0; i<N; i++) for (int j=0; j<N; j++) P[i][j]=P[i][j]-(mw[i]^w[j]),
xue@1 2234 delete[] mw;
xue@1 2235 }
xue@1 2236 delete[] w;
xue@1 2237 if (List) List->Add(P, 2);
xue@1 2238 return P;
xue@1 2239 }//Unitary
xue@1 2240 //wrapper functions
xue@1 2241 double** Unitary(int N, double* x, double* y, MList* List){return Unitary(N, 0, x, y, List);}
xue@1 2242 cdouble** Unitary(int N, cdouble* x, cdouble* y, MList* List){return Unitary(N, 0, x, y, List);}
xue@1 2243
xue@1 2244
xue@1 2245