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
|