00001 // matmath.cc 00002 // SuperMix version 1.0 C++ source file 00003 // 00004 // Copyright (c) 1999 California Institute of Technology. 00005 // All rights reserved. 00006 // 00007 // Redistribution and use in source and binary forms for noncommercial 00008 // purposes are permitted provided that the above copyright notice and 00009 // this paragraph are duplicated in all such forms and that any 00010 // documentation and other materials related to such distribution and 00011 // use acknowledge that the software was developed by California 00012 // Institute of Technology. Redistribution and/or use in source or 00013 // binary forms is not permitted for any commercial purpose. Use of 00014 // this software does not include a permitted use of the Institute's 00015 // name or trademark for any purpose. 00016 // 00017 // DISCLAIMER: 00018 // THIS SOFTWARE AND/OR RELATED MATERIALS ARE PROVIDED "AS-IS" WITHOUT 00019 // WARRANTY OF ANY KIND INCLUDING ANY WARRANTIES OF PERFORMANCE OR 00020 // MERCHANTABILITY OR FITNESS FOR A PARTICULAR USE OR PURPOSE (AS SET 00021 // FORTH IN UCC 23212-2313) OR FOR ANY PURPOSE WHATSOEVER, FOR THE 00022 // LICENSED PRODUCT, HOWEVER USED. IN NO EVENT SHALL CALTECH/JPL BE 00023 // LIABLE FOR ANY DAMAGES AND/OR COSTS, INCLUDING BUT NOT LIMITED TO 00024 // INCIDENTAL OR CONSEQUENTIAL DAMAGES OF ANY KIND, INCLUDING ECONOMIC 00025 // DAMAGE OR INJURY TO PROPERTY AND LOST PROFITS, REGARDLESS OF 00026 // WHETHER CALTECH/JPL SHALL BE ADVISED, HAVE REASON TO KNOW, OR IN 00027 // FACT SHALL KNOW OF THE POSSIBILITY. THE USER BEARS ALL RISK 00028 // RELATING TO QUALITY AND PERFORMANCE OF THE SOFTWARE AND/OR RELATED 00029 // MATERIALS. 00030 // 00031 // Change history: 00032 // 7/6/99: changed "table" to "matrix" 00033 // 6/28/99: Added norm() and max_norm() for vectors and tables 00034 // 11/11/98: Changed to use new vector and table accessing 00035 // 11/10/98: Minor mods to support new vector accessing 00036 // 11/2/98: Added scalerow() 00037 // 10/7/98: Added fast square matrix routines 00038 // 7/10/98: Added a new linterp(). 00039 // 2/6/98: Added lookup(), linterp(). Tested o.k. 2/12/98. 00040 // 1/9/98: Found a bug in row(), col() dimensioning. Fixed it. 00041 // 12/12/97: "fully" tested with calc 00042 // 11/24/97: Added mixed vector-table operations and functions 00043 // 11/18/97: Filling in table math functions 00044 // 11/17/97: Solver complete; real_table version tests o.k. 00045 // 11/11/97: real_vector and complex_vector test o.k. with vcalc. 00046 // 11/10/97: real_vector operations test o.k. with vcalc. 00047 // 11/8/97: First version. 00048 00049 #include "matmath.h" 00050 #include "Amath.h" 00051 00052 // ************************************************************************ 00053 // Helper functions: 00054 00055 inline int min(int a, int b) { return (a < b)? a : b; } 00056 inline int max(int a, int b) { return (a > b)? a : b; } 00057 inline int length(int a, int b) { int n = b - a + 1; return (n < 0)? 0 : n; } 00058 00059 // Determine the result index mode which maximizes number of elements: 00060 static v_index_mode ResultModeMax(const v_index_mode a, const v_index_mode b) 00061 { 00062 if((a == Index_S)||(b == Index_S)) return Index_S; 00063 else if ((a == Index_C)||(b == Index_C)) return Index_C; 00064 else return Index_1; 00065 } 00066 00067 // Determine the result index mode which minimizes number of elements: 00068 static v_index_mode ResultModeMin(const v_index_mode a, const v_index_mode b) 00069 { 00070 if((a == Index_1)||(b == Index_1)) return Index_1; 00071 else if ((a == Index_C)||(b == Index_C)) return Index_C; 00072 else return Index_S; 00073 } 00074 00075 // Determine the maxindex which maximizes the number of elements: 00076 inline int ResultIndexMax(const int i1, const int i2) 00077 { return max(i1,i2); } 00078 00079 // Determine the maxindex which minimizes the number of elements: 00080 inline int ResultIndexMin(const int i1, const int i2) 00081 { return min(i1,i2); } 00082 00083 00084 // ************************************************************************ 00085 // Vector and Matrix norms: 00086 00087 static double norm_accumulator; // static, so confined to this file 00088 00089 static inline void norm_add(double x) 00090 { norm_accumulator += x*x; } 00091 00092 static inline void norm_add(const Complex & x) 00093 { norm_accumulator += norm(x); } 00094 00095 static inline void norm_bigger(double x) 00096 { x *= x; if (x > norm_accumulator) norm_accumulator = x; } 00097 00098 static inline void norm_bigger(const Complex & x) 00099 { double u = norm(x); if (u > norm_accumulator) norm_accumulator = u; } 00100 00101 double max_norm(const real_vector & x) 00102 { 00103 register int i; 00104 register int m = x.maxindex(); 00105 norm_accumulator = 0; 00106 for (i = x.minindex(); i <= m; ++i) 00107 norm_bigger(x[i]); 00108 return norm_accumulator; 00109 } 00110 00111 double max_norm(const complex_vector & x) 00112 { 00113 register int i; 00114 register int m = x.maxindex(); 00115 norm_accumulator = 0; 00116 for (i = x.minindex(); i <= m; ++i) 00117 norm_bigger(x[i]); 00118 return norm_accumulator; 00119 } 00120 00121 double norm(const real_matrix & x) 00122 { 00123 register int i; 00124 register int mR = x.Rmaxindex(); 00125 register int j; 00126 register int mL = x.Lmaxindex(); 00127 norm_accumulator = 0; 00128 for (j = x.Lminindex(); j <= mL; ++j) 00129 for (i = x.Rminindex(); i <= mR; ++i) 00130 norm_add(x[j][i]); 00131 return norm_accumulator; 00132 } 00133 00134 double norm(const complex_matrix & x) 00135 { 00136 register int i; 00137 register int mR = x.Rmaxindex(); 00138 register int j; 00139 register int mL = x.Lmaxindex(); 00140 norm_accumulator = 0; 00141 for (j = x.Lminindex(); j <= mL; ++j) 00142 for (i = x.Rminindex(); i <= mR; ++i) 00143 norm_add(x[j][i]); 00144 return norm_accumulator; 00145 } 00146 00147 double max_norm(const real_matrix & x) 00148 { 00149 register int i; 00150 register int mR = x.Rmaxindex(); 00151 register int j; 00152 register int mL = x.Lmaxindex(); 00153 norm_accumulator = 0; 00154 for (j = x.Lminindex(); j <= mL; ++j) 00155 for (i = x.Rminindex(); i <= mR; ++i) 00156 norm_bigger(x[j][i]); 00157 return norm_accumulator; 00158 } 00159 00160 double max_norm(const complex_matrix & x) 00161 { 00162 register int i; 00163 register int mR = x.Rmaxindex(); 00164 register int j; 00165 register int mL = x.Lmaxindex(); 00166 norm_accumulator = 0; 00167 for (j = x.Lminindex(); j <= mL; ++j) 00168 for (i = x.Rminindex(); i <= mR; ++i) 00169 norm_bigger(x[j][i]); 00170 return norm_accumulator; 00171 } 00172 00173 00174 00175 // ************************************************************************ 00176 // Vector Functions: Overloaded Operators for two Vectors, scalemult(), scalediv() 00177 00178 real_vector operator +(const real_vector & x, const real_vector & y) 00179 { 00180 // determine answer mode and size, then define it: 00181 v_index_mode mode = ResultModeMax(x.mode,y.mode); 00182 int size = ResultIndexMax(x.maxindex(),y.maxindex()); 00183 if (mode == Index_C) ++size; // need to fix size for Index_C only 00184 real_vector ans(size,mode); // construction initializes to all 0's 00185 00186 // now calculate answer: 00187 ans += x; ans += y; 00188 return ans; 00189 } 00190 00191 real_vector operator -(const real_vector & x, const real_vector & y) 00192 { 00193 // determine answer mode and size, then define it: 00194 v_index_mode mode = ResultModeMax(x.mode,y.mode); 00195 int size = ResultIndexMax(x.maxindex(),y.maxindex()); 00196 if (mode == Index_C) ++size; // need to fix size for Index_C only 00197 real_vector ans(size,mode); // construction initializes to all 0's 00198 00199 // now calculate answer: 00200 ans += x; ans -= y; 00201 return ans; 00202 } 00203 00204 double operator *(const real_vector & x, const real_vector & y) 00205 { 00206 double sum = 0; 00207 register int i = max(x.minindex(), y.minindex()); 00208 register int limit = min(x.maxindex(), y.maxindex()); 00209 for ( ; i <= limit; ++i) 00210 sum += (x[i] * y[i]); 00211 return sum; 00212 } 00213 00214 complex_vector operator +(const complex_vector & x, const complex_vector & y) 00215 { 00216 // determine answer mode and size, then define it: 00217 v_index_mode mode = ResultModeMax(x.mode,y.mode); 00218 int size = ResultIndexMax(x.maxindex(),y.maxindex()); 00219 if (mode == Index_C) ++size; // need to fix size for Index_C only 00220 complex_vector ans(size,mode); // construction initializes to all 0's 00221 00222 // now calculate answer: 00223 ans += x; ans += y; 00224 return ans; 00225 } 00226 00227 complex_vector operator -(const complex_vector & x, const complex_vector & y) 00228 { 00229 // determine answer mode and size, then define it: 00230 v_index_mode mode = ResultModeMax(x.mode,y.mode); 00231 int size = ResultIndexMax(x.maxindex(),y.maxindex()); 00232 if (mode == Index_C) ++size; // need to fix size for Index_C only 00233 complex_vector ans(size,mode); // construction initializes to all 0's 00234 00235 // now calculate answer: 00236 ans += x; ans -= y; 00237 return ans; 00238 } 00239 00240 Complex operator *(const complex_vector & x, const complex_vector & y) 00241 { 00242 Complex sum = 0; 00243 register int i = max(x.minindex(), y.minindex()); 00244 register int limit = min(x.maxindex(), y.maxindex()); 00245 for ( ; i <= limit; ++i) 00246 sum += (x[i] * y[i]); 00247 return sum; 00248 } 00249 00250 complex_vector operator +(const real_vector & x, const complex_vector & y) 00251 { 00252 // determine answer mode and size, then define it: 00253 v_index_mode mode = ResultModeMax(x.mode,y.mode); 00254 int size = ResultIndexMax(x.maxindex(),y.maxindex()); 00255 if (mode == Index_C) ++size; // need to fix size for Index_C only 00256 complex_vector ans(size,mode); // construction initializes to all 0's 00257 00258 // now calculate answer: 00259 ans += x; ans += y; 00260 return ans; 00261 } 00262 00263 complex_vector operator -(const real_vector & x, const complex_vector & y) 00264 { 00265 // determine answer mode and size, then define it: 00266 v_index_mode mode = ResultModeMax(x.mode,y.mode); 00267 int size = ResultIndexMax(x.maxindex(),y.maxindex()); 00268 if (mode == Index_C) ++size; // need to fix size for Index_C only 00269 complex_vector ans(size,mode); // construction initializes to all 0's 00270 00271 // now calculate answer: 00272 ans += x; ans -= y; 00273 return ans; 00274 } 00275 00276 complex_vector operator -(const complex_vector & x, const real_vector & y) 00277 { 00278 // determine answer mode and size, then define it: 00279 v_index_mode mode = ResultModeMax(x.mode,y.mode); 00280 int size = ResultIndexMax(x.maxindex(),y.maxindex()); 00281 if (mode == Index_C) ++size; // need to fix size for Index_C only 00282 complex_vector ans(size,mode); // construction initializes to all 0's 00283 00284 // now calculate answer: 00285 ans += x; ans -= y; 00286 return ans; 00287 } 00288 00289 Complex operator *(const real_vector & x, const complex_vector & y) 00290 { 00291 Complex sum = 0; 00292 register int i = max(x.minindex(), y.minindex()); 00293 register int limit = min(x.maxindex(), y.maxindex()); 00294 for ( ; i <= limit; ++i) 00295 sum += (x[i] * y[i]); 00296 return sum; 00297 } 00298 00299 real_vector scalemult(const real_vector & x, const real_vector & y) 00300 { 00301 // determine answer mode and size, then define it: 00302 v_index_mode mode = ResultModeMax(x.mode,y.mode); 00303 int size = ResultIndexMax(x.maxindex(),y.maxindex()); 00304 if (mode == Index_C) ++size; // need to fix size for Index_C only 00305 real_vector ans(size,mode); // construction initializes to all 0's 00306 00307 // now calculate answer: 00308 for(int i = ans.minindex(); i <= ans.maxindex(); ++i) 00309 ans[i] = x.read(i)*y.read(i); 00310 return ans; 00311 } 00312 00313 real_vector scalediv(const real_vector & x, const real_vector & y) 00314 { 00315 // determine answer mode and size, then define it: 00316 v_index_mode mode = ResultModeMax(x.mode,y.mode); 00317 int size = ResultIndexMax(x.maxindex(),y.maxindex()); 00318 if (mode == Index_C) ++size; // need to fix size for Index_C only 00319 real_vector ans(size,mode); // construction initializes to all 0's 00320 00321 // now calculate answer: 00322 for(int i = ans.minindex(); i <= ans.maxindex(); ++i) 00323 ans[i] = x.read(i)/y.read(i); 00324 return ans; 00325 } 00326 00327 complex_vector scalemult(const complex_vector & x, const complex_vector & y) 00328 { 00329 // determine answer mode and size, then define it: 00330 v_index_mode mode = ResultModeMax(x.mode,y.mode); 00331 int size = ResultIndexMax(x.maxindex(),y.maxindex()); 00332 if (mode == Index_C) ++size; // need to fix size for Index_C only 00333 complex_vector ans(size,mode); // construction initializes to all 0's 00334 00335 // now calculate answer: 00336 for(int i = ans.minindex(); i <= ans.maxindex(); ++i) 00337 ans[i] = x.read(i)*y.read(i); 00338 return ans; 00339 } 00340 00341 complex_vector scalediv(const complex_vector & x, const complex_vector & y) 00342 { 00343 // determine answer mode and size, then define it: 00344 v_index_mode mode = ResultModeMax(x.mode,y.mode); 00345 int size = ResultIndexMax(x.maxindex(),y.maxindex()); 00346 if (mode == Index_C) ++size; // need to fix size for Index_C only 00347 complex_vector ans(size,mode); // construction initializes to all 0's 00348 00349 // now calculate answer: 00350 for(int i = ans.minindex(); i <= ans.maxindex(); ++i) 00351 ans[i] = x.read(i)/y.read(i); 00352 return ans; 00353 } 00354 00355 complex_vector scalemult(const real_vector & x, const complex_vector & y) 00356 { 00357 // determine answer mode and size, then define it: 00358 v_index_mode mode = ResultModeMax(x.mode,y.mode); 00359 int size = ResultIndexMax(x.maxindex(),y.maxindex()); 00360 if (mode == Index_C) ++size; // need to fix size for Index_C only 00361 complex_vector ans(size,mode); // construction initializes to all 0's 00362 00363 // now calculate answer: 00364 for(int i = ans.minindex(); i <= ans.maxindex(); ++i) 00365 ans[i] = x.read(i)*y.read(i); 00366 return ans; 00367 } 00368 00369 complex_vector scalediv(const real_vector & x, const complex_vector & y) 00370 { 00371 // determine answer mode and size, then define it: 00372 v_index_mode mode = ResultModeMax(x.mode,y.mode); 00373 int size = ResultIndexMax(x.maxindex(),y.maxindex()); 00374 if (mode == Index_C) ++size; // need to fix size for Index_C only 00375 complex_vector ans(size,mode); // construction initializes to all 0's 00376 00377 // now calculate answer: 00378 for(int i = ans.minindex(); i <= ans.maxindex(); ++i) 00379 ans[i] = x.read(i)/y.read(i); 00380 return ans; 00381 } 00382 00383 complex_vector scalediv(const complex_vector & x, const real_vector & y) 00384 { 00385 // determine answer mode and size, then define it: 00386 v_index_mode mode = ResultModeMax(x.mode,y.mode); 00387 int size = ResultIndexMax(x.maxindex(),y.maxindex()); 00388 if (mode == Index_C) ++size; // need to fix size for Index_C only 00389 complex_vector ans(size,mode); // construction initializes to all 0's 00390 00391 // now calculate answer: 00392 for(int i = ans.minindex(); i <= ans.maxindex(); ++i) 00393 ans[i] = x.read(i)/y.read(i); 00394 return ans; 00395 } 00396 00397 00398 // ************************************************************************ 00399 // Vector Functions: Overloaded Operators for Vector and Scalar 00400 00401 real_vector operator +(const real_vector & v, const double s) 00402 { real_vector ans; ans = v; ans += s; return ans; } 00403 00404 real_vector operator -(const real_vector & v, const double s) 00405 { real_vector ans; ans = v; ans -= s; return ans; } 00406 00407 real_vector operator *(const real_vector & v, const double s) 00408 { real_vector ans; ans = v; ans *= s; return ans; } 00409 00410 real_vector operator /(const real_vector & v, const double s) 00411 { real_vector ans; ans = v; ans /= s; return ans; } 00412 00413 complex_vector operator +(const complex_vector & v, const Complex s) 00414 { complex_vector ans; ans = v; ans += s; return ans; } 00415 00416 complex_vector operator -(const complex_vector & v, const Complex s) 00417 { complex_vector ans; ans = v; ans -= s; return ans; } 00418 00419 complex_vector operator *(const complex_vector & v, const Complex s) 00420 { complex_vector ans; ans = v; ans *= s; return ans; } 00421 00422 complex_vector operator /(const complex_vector & v, const Complex s) 00423 { complex_vector ans; ans = v; ans /= s; return ans; } 00424 00425 complex_vector operator +(const real_vector & v, const Complex s) 00426 { complex_vector ans; ans = v; ans += s; return ans; } 00427 00428 complex_vector operator -(const real_vector & v, const Complex s) 00429 { complex_vector ans; ans = v; ans -= s; return ans; } 00430 00431 complex_vector operator *(const real_vector & v, const Complex s) 00432 { complex_vector ans; ans = v; ans *= s; return ans; } 00433 00434 complex_vector operator /(const real_vector & v, const Complex s) 00435 { complex_vector ans; ans = v; ans /= s; return ans; } 00436 00437 00438 // ************************************************************************ 00439 // Matrix Functions: Unary Operations 00440 00441 complex_matrix transpose(const complex_matrix &U) 00442 { 00443 // Make V with transposed modes and sizes: 00444 complex_matrix V(0, 0, U.Rmode, U.Lmode); 00445 V.resize(U.Rmaxindex(), U.Lmaxindex()); 00446 // Now copy the elements: 00447 for (int i = V.Lminindex(); i <= V.Lmaxindex(); ++i) { 00448 register int limit = V.Rmaxindex(); 00449 register int j; 00450 for (j = V.Rminindex(); j <= limit; ++j) 00451 V[i][j] = U[j][i]; 00452 } 00453 return V; 00454 } 00455 00456 real_matrix transpose(const real_matrix &X) 00457 { 00458 // Make Y with transposed modes and sizes: 00459 real_matrix Y(0, 0, X.Rmode, X.Lmode); 00460 Y.resize(X.Rmaxindex(), X.Lmaxindex()); 00461 // Now copy the elements: 00462 for (int i = Y.Lminindex(); i <= Y.Lmaxindex(); ++i) { 00463 register int limit = Y.Rmaxindex(); 00464 register int j; 00465 for (j = Y.Rminindex(); j <= limit; ++j) 00466 Y[i][j] = X[j][i]; 00467 } 00468 return Y; 00469 } 00470 00471 00472 // ************************************************************************ 00473 // Matrix Functions: Overloaded Operators for two Matrices 00474 00475 complex_matrix operator +(const complex_matrix & B, const complex_matrix & C) 00476 { complex_matrix A(0); return A.add(B,C); } 00477 00478 complex_matrix operator +(const real_matrix & B, const complex_matrix & C) 00479 { complex_matrix A(0); return A.add(B,C); } 00480 00481 complex_matrix operator +(const complex_matrix & B, const real_matrix & C) 00482 { complex_matrix A(0); return A.add(B,C); } 00483 00484 real_matrix operator +(const real_matrix & B, const real_matrix & C) 00485 { real_matrix A(0); return A.add(B,C); } 00486 00487 complex_matrix operator -(const complex_matrix & B, const complex_matrix & C) 00488 { complex_matrix A(0); return A.sub(B,C); } 00489 00490 complex_matrix operator -(const real_matrix & B, const complex_matrix & C) 00491 { complex_matrix A(0); return A.sub(B,C); } 00492 00493 complex_matrix operator -(const complex_matrix & B, const real_matrix & C) 00494 { complex_matrix A(0); return A.sub(B,C); } 00495 00496 real_matrix operator -(const real_matrix & B, const real_matrix & C) 00497 { real_matrix A(0); return A.sub(B,C); } 00498 00499 complex_matrix operator *(const complex_matrix & B, const complex_matrix & C) 00500 { 00501 // make the result look like B in the left index, C in the right index: 00502 complex_matrix A(0, 0, B.Lmode, C.Rmode); 00503 A.resize(B.Lmaxindex(), C.Rmaxindex()); 00504 // now fill the result: 00505 int i, j; 00506 int low = max(B.Rminindex(), C.Lminindex()); 00507 int hi = min(B.Rmaxindex(), C.Lmaxindex()); 00508 Complex sum; 00509 register int k; 00510 for(i = A.Lminindex(); i <= A.Lmaxindex(); ++i) 00511 for(j = A.Rminindex(); j <= A.Rmaxindex(); ++j) { 00512 for (sum = 0, k = low; k <= hi; ++k) 00513 sum += B[i][k] * C[k][j]; 00514 A[i][j] = sum; 00515 } 00516 return A; 00517 } 00518 00519 complex_matrix operator *(const real_matrix & B, const complex_matrix & C) 00520 { 00521 // make the result look like B in the left index, C in the right index: 00522 complex_matrix A(0, 0, B.Lmode, C.Rmode); 00523 A.resize(B.Lmaxindex(), C.Rmaxindex()); 00524 // now fill the result: 00525 int i, j; 00526 int low = max(B.Rminindex(), C.Lminindex()); 00527 int hi = min(B.Rmaxindex(), C.Lmaxindex()); 00528 Complex sum; 00529 register int k; 00530 for(i = A.Lminindex(); i <= A.Lmaxindex(); ++i) 00531 for(j = A.Rminindex(); j <= A.Rmaxindex(); ++j) { 00532 for (sum = 0, k = low; k <= hi; ++k) 00533 sum += B[i][k] * C[k][j]; 00534 A[i][j] = sum; 00535 } 00536 return A; 00537 } 00538 00539 complex_matrix operator *(const complex_matrix & B, const real_matrix & C) 00540 { 00541 // make the result look like B in the left index, C in the right index: 00542 complex_matrix A(0, 0, B.Lmode, C.Rmode); 00543 A.resize(B.Lmaxindex(), C.Rmaxindex()); 00544 // now fill the result: 00545 int i, j; 00546 int low = max(B.Rminindex(), C.Lminindex()); 00547 int hi = min(B.Rmaxindex(), C.Lmaxindex()); 00548 Complex sum; 00549 register int k; 00550 for(i = A.Lminindex(); i <= A.Lmaxindex(); ++i) 00551 for(j = A.Rminindex(); j <= A.Rmaxindex(); ++j) { 00552 for (sum = 0, k = low; k <= hi; ++k) 00553 sum += B[i][k] * C[k][j]; 00554 A[i][j] = sum; 00555 } 00556 return A; 00557 } 00558 00559 real_matrix operator *(const real_matrix & B, const real_matrix & C) 00560 { 00561 // make the result look like B in the left index, C in the right index: 00562 real_matrix A(0, 0, B.Lmode, C.Rmode); 00563 A.resize(B.Lmaxindex(), C.Rmaxindex()); 00564 // now fill the result: 00565 int i, j; 00566 int low = max(B.Rminindex(), C.Lminindex()); 00567 int hi = min(B.Rmaxindex(), C.Lmaxindex()); 00568 double sum; 00569 register int k; 00570 for(i = A.Lminindex(); i <= A.Lmaxindex(); ++i) 00571 for(j = A.Rminindex(); j <= A.Rmaxindex(); ++j) { 00572 for (sum = 0, k = low; k <= hi; ++k) 00573 sum += B[i][k] * C[k][j]; 00574 A[i][j] = sum; 00575 } 00576 return A; 00577 } 00578 00579 00580 // ************************************************************************ 00581 // Matrix Functions: Overloaded Operators for Matrix and Scalar 00582 00583 real_matrix operator +(const real_matrix & A, const double s) 00584 { real_matrix ans; ans = A; ans += s; return ans; } 00585 00586 real_matrix operator -(const real_matrix & A, const double s) 00587 { real_matrix ans; ans = A; ans -= s; return ans; } 00588 00589 real_matrix operator *(const real_matrix & A, const double s) 00590 { real_matrix ans; ans = A; ans *= s; return ans; } 00591 00592 real_matrix operator /(const real_matrix & A, const double s) 00593 { real_matrix ans; ans = A; ans /= s; return ans; } 00594 00595 complex_matrix operator +(const complex_matrix & A, const Complex s) 00596 { complex_matrix ans; ans = A; ans += s; return ans; } 00597 00598 complex_matrix operator -(const complex_matrix & A, const Complex s) 00599 { complex_matrix ans; ans = A; ans -= s; return ans; } 00600 00601 complex_matrix operator *(const complex_matrix & A, const Complex s) 00602 { complex_matrix ans; ans = A; ans *= s; return ans; } 00603 00604 complex_matrix operator /(const complex_matrix & A, const Complex s) 00605 { complex_matrix ans; ans = A; ans /= s; return ans; } 00606 00607 complex_matrix operator +(const real_matrix & A, const Complex s) 00608 { complex_matrix ans; ans = A; ans += s; return ans; } 00609 00610 complex_matrix operator -(const real_matrix & A, const Complex s) 00611 { complex_matrix ans; ans = A; ans -= s; return ans; } 00612 00613 complex_matrix operator *(const real_matrix & A, const Complex s) 00614 { complex_matrix ans; ans = A; ans *= s; return ans; } 00615 00616 complex_matrix operator /(const real_matrix & A, const Complex s) 00617 { complex_matrix ans; ans = A; ans /= s; return ans; } 00618 00619 00620 // ************************************************************************ 00621 // Matrix Functions: lookup and linterp 00622 00623 // Refer to FR's bsearch.cc for a fully commented description of the 00624 // algorithm; also notebook, pg 39. 00625 00626 int lookup(const double x, const real_matrix & A, const int row) 00627 { 00628 int b, t, test; // b,t index limits, test index in the middle 00629 00630 b = A.Rminindex(); t = A.Rmaxindex(); 00631 if (t < b) return b; // empty matrix 00632 00633 while (b + 1 < t) { 00634 test = (b + t) / 2; // we know that: b < test < t here 00635 if ( A.read(row,test) <= x ) 00636 b = test; 00637 else 00638 t = test; 00639 } 00640 00641 return (A.read(row,t) <= x) ? t : b; 00642 } 00643 00644 int lookup(const double x, const complex_matrix & A, const int row) 00645 { 00646 int b, t, test; // b,t index limits, test index in the middle 00647 00648 b = A.Rminindex(); t = A.Rmaxindex(); 00649 if (t < b) return b; // empty matrix 00650 00651 while (b + 1 < t) { 00652 test = (b + t) / 2; // we know that: b < test < t here 00653 if ( A.read(row,test).real <= x ) 00654 b = test; 00655 else 00656 t = test; 00657 } 00658 00659 return (A.read(row,t).real <= x) ? t : b; 00660 } 00661 00662 // Refer to FR notebook, pp 27-28,46 for details. 00663 00664 double linterp(const double x, const real_matrix & A, 00665 const int n1, const int n2) 00666 { 00667 int i = lookup(x, A, n1); // lower index (maybe) 00668 00669 int j = (i < A.Rmaxindex()) ? i+1 : i-1; // garbage if A empty 00670 00671 00672 double m; //slope 00673 double xi = A.read(n1,i); double xj = A.read(n1,j); 00674 double yi = A.read(n2,i); double yj = A.read(n2,j); 00675 00676 if (xi != xj) { 00677 m = (yi - yj)/(xi - xj); // m = Dy/Dx 00678 return yi + m*(x - xi); // an extrapolation if x outside matrix 00679 } 00680 else //slope is vertical, method fails, return 0.0 (why not?) 00681 return 0.0; 00682 } 00683 00684 Complex linterp(const double x, const complex_matrix & A, 00685 const int n1, const int n2) 00686 { 00687 int i = lookup(x, A, n1); // lower index (maybe) 00688 00689 int j = (i < A.Rmaxindex()) ? i+1 : i-1; // garbage if A empty 00690 00691 00692 Complex m; //slope 00693 double xi = A.read(n1,i).real; double xj = A.read(n1,j).real; 00694 Complex yi = A.read(n2,i); Complex yj = A.read(n2,j); 00695 00696 if (xi != xj) { 00697 m = (yi - yj)/(xi - xj); // m = Dy/Dx 00698 return yi + m*(x - xi); // an extrapolation if x outside matrix 00699 } 00700 else //slope is vertical, method fails, return 0.0 (why not?) 00701 return Complex(0.0); 00702 } 00703 00704 real_vector linterp(const double x, const real_matrix & A, 00705 const int n) 00706 { 00707 int i = lookup(x, A, n); // lower index (maybe) 00708 int j = (i < A.Rmaxindex()) ? i+1 : i-1; // garbage if A empty 00709 double xi = A.read(n,i); double xj = A.read(n,j); 00710 if(xi == xj) return real_vector(0); // vertical slope; empty return vector 00711 00712 double f = 1/(xi - xj); // factor for calculating slope 00713 real_vector result(A.Lmode); result.resize(A.Lmaxindex()); 00714 for(int row = result.minindex(); row <= result.maxindex(); ++row) { 00715 double yi = A.read(row,i); double yj = A.read(row,j); 00716 double m = f*(yi - yj); // slope 00717 result[row] = yi + m*(x - xi); // an extrapolation if x outside matrix 00718 } 00719 result.get(n) = x; // the independent variable 00720 return result; 00721 } 00722 00723 complex_vector linterp(const double x, const complex_matrix & A, 00724 const int n) 00725 { 00726 int i = lookup(x, A, n); // lower index (maybe) 00727 int j = (i < A.Rmaxindex()) ? i+1 : i-1; // garbage if A empty 00728 double xi = A.read(n,i).real; double xj = A.read(n,j).real; 00729 if(xi == xj) return complex_vector(0); // vertical slope; empty return vector 00730 00731 double f = 1/(xi - xj); // factor for calculating slope 00732 complex_vector result(A.Lmode); result.resize(A.Lmaxindex()); 00733 for(int row = result.minindex(); row <= result.maxindex(); ++row) { 00734 Complex yi = A.read(row,i); Complex yj = A.read(row,j); 00735 Complex m = f*(yi - yj); // slope 00736 result[row] = yi + m*(x - xi); // an extrapolation if x outside matrix 00737 } 00738 result.get(n) = x; // the independent variable (imaginary part = 0) 00739 return result; 00740 } 00741 00742 00743 // ************************************************************************ 00744 // Matrix Functions: scalerow 00745 00746 real_matrix & scalerow(const int n, real_matrix & X, const double y) 00747 { 00748 if ((n < X.Lminindex())||(n > X.Lmaxindex())) 00749 return X; // no action required for n out of range 00750 00751 int len = length(X.Rminindex(), X.Rmaxindex()); 00752 Ascale(&X[n][X.Rminindex()], y, len); 00753 return X; 00754 } 00755 00756 complex_matrix & scalerow(const int n, complex_matrix & U, const Complex v) 00757 { 00758 if ((n < U.Lminindex())||(n > U.Lmaxindex())) 00759 return U; // no action required for n out of range 00760 00761 int len = length(U.Rminindex(), U.Rmaxindex()); 00762 Ascale(&U[n][U.Rminindex()], v, len); 00763 return U; 00764 } 00765 00766 00767 // ************************************************************************ 00768 // Mixed Matrix and Vector Routines: Get a Row or Column of a Matrix 00769 00770 real_vector row(const int n, const real_matrix & X) 00771 { 00772 real_vector v(0, X.Rmode); 00773 v.resize(X.Rmaxindex()); 00774 for(int i = v.minindex(); i <= v.maxindex(); ++i) 00775 v[i] = X.read(n,i); 00776 return v; 00777 } 00778 00779 real_vector col(const int n, const real_matrix & X) 00780 { 00781 real_vector v(0, X.Lmode); 00782 v.resize(X.Lmaxindex()); 00783 for(int i = v.minindex(); i <= v.maxindex(); ++i) 00784 v[i] = X.read(i,n); 00785 return v; 00786 } 00787 00788 complex_vector row(const int n, const complex_matrix & X) 00789 { 00790 complex_vector v(0, X.Rmode); 00791 v.resize(X.Rmaxindex()); 00792 for(int i = v.minindex(); i <= v.maxindex(); ++i) 00793 v[i] = X.read(n,i); 00794 return v; 00795 } 00796 00797 complex_vector col(const int n, const complex_matrix & X) 00798 { 00799 complex_vector v(0, X.Lmode); 00800 v.resize(X.Lmaxindex()); 00801 for(int i = v.minindex(); i <= v.maxindex(); ++i) 00802 v[i] = X.read(i,n); 00803 return v; 00804 } 00805 00806 // ************************************************************************ 00807 // Mixed Matrix and Vector Routines: Overloaded Operator * 00808 00809 real_vector operator *(const real_matrix & X, const real_vector & y) 00810 { 00811 return col(1, X * real_matrix(y)); 00812 } 00813 00814 complex_vector operator *(const complex_matrix & U, const complex_vector & v) 00815 { 00816 return col(1, U * complex_matrix(v)); 00817 } 00818 00819 complex_vector operator *(const real_matrix & X, const complex_vector & v) 00820 { 00821 return col(1, X * complex_matrix(v)); 00822 } 00823 00824 complex_vector operator *(const complex_matrix & U, const real_vector & y) 00825 { 00826 return col(1, U * real_matrix(y)); 00827 } 00828 00829 00830 // ************************************************************************ 00831 // The Matrix Solver, and helper routines: 00832 00833 // Real Version: 00834 00835 // Solves AX == B and returns X. If it's unable to solve the system, 00836 // then X will be empty. 00837 real_matrix solve(const real_matrix & A, const real_matrix & B); 00838 00839 real_vector solve(const real_matrix & A, const real_vector & b) 00840 { 00841 return col(1, solve(A, real_matrix(b))); 00842 } 00843 00844 // checks sizes of A and B in AX == B for solvability, 00845 // and puts lengths of X into n and m 00846 static int sizecheck( 00847 const real_matrix & A, // The coefficient matrix 00848 const real_matrix & B, // The RHS matrix 00849 int & n, // The column length of X 00850 int & m // The row length of X 00851 ); // Returns 0 if not solvable, 1 if solvable 00852 00853 // copies A and B into the previously-sized C so that C is A|B. 00854 // C must be properly sized and have Index_C in both dimensions 00855 static void augment(real_matrix & C, 00856 const real_matrix & A, 00857 const real_matrix & B 00858 ); 00859 00860 // scale the rows of C if necessary in preparation for solving 00861 static void scale(real_matrix & C); 00862 00863 // performs gaussian elimination of the augmented matrix C, with 00864 // partial pivoting. Does not back-substitute. Returns 0 if C 00865 // represents a singular system, otherwise returns 1 00866 static int triangle(real_matrix & C); 00867 00868 // performs back-substitution in the solvable system C, writing the 00869 // results into the former locations of the RHS elements 00870 static void backsub(real_matrix & C); 00871 00872 // transcribes the results in C into the proper locations in X 00873 static void copyresult(real_matrix & X, const real_matrix & C); 00874 00875 // pivot row i of C with the rows following it. Returns 0 if a pivot 00876 // != 0 cannot be found (so C is singular), else returns 1. 00877 // (used by triangle()) 00878 static int pivot(int i, real_matrix & C); 00879 00880 // ------------------------------------------------------------------------ 00881 // the solver definitions: 00882 00883 // Solves AX == B and returns X. If it's unable to solve the system, 00884 // then X will be empty. 00885 real_matrix solve(const real_matrix & A, const real_matrix & B) 00886 { 00887 real_matrix X(0,0,Index_1,Index_1); // the solution (empty for now) 00888 int n, m; // the column length and row length of X 00889 00890 // Calculate n and m and check compatibility of A and B: 00891 if ( ! sizecheck(A, B, n, m) ) 00892 // sizecheck returns 0 if the geometries of A and B aren't o.k. 00893 return X; // failure: returns the empty X 00894 00895 // Passed sizecheck(). Make the augmented matrix C from A and B: 00896 real_matrix C(n, n+m, Index_C, Index_C); 00897 augment(C, A, B); 00898 scale(C); // individually scales each row to improve solver accuracy 00899 00900 // Perform the Gaussian Elimination, with X values replacing B in C: 00901 if ( ! triangle(C)) 00902 // triangle() returns 0 if A is singular, so system can't be solved 00903 return X; // failure: returns the empty X 00904 backsub(C); 00905 00906 // Now resize X and copy the results into it, then return: 00907 X.reallocate(A.Rsize, B.Rsize, A.Rmode, B.Rmode); 00908 X.Lmaxindex(A.Rmaxindex()); 00909 X.Rmaxindex(B.Rmaxindex()); 00910 copyresult(X, C); 00911 return X; 00912 } 00913 00914 // Uses solve() to find the inverse of a matrix. If the inverse doesn't 00915 // exist, then the returned matrix will be empty. Note: the index modes and 00916 // valid index ranges of A must be the same in both dimensions for an 00917 // inverse to exist (A is square). 00918 real_matrix inverse(const real_matrix & A) 00919 { 00920 real_matrix B(0); // will become the RHS for solve() 00921 00922 if ((A.Rmode == A.Lmode)&&(A.Rmaxindex() == A.Lmaxindex())) { 00923 // then A may be invertible, so set up the RHS for solve() 00924 B.resize(A); 00925 B.diagonal(1.0); 00926 } 00927 // if the above if failed, then the RHS is empty, and so will be the 00928 // returned matrix from solve() 00929 return solve(A,B); 00930 } 00931 00932 // checks sizes of A and B in AX == B for solvability, 00933 // and puts lengths of X into n and m 00934 static int sizecheck( 00935 const real_matrix & A, // The coefficient matrix 00936 const real_matrix & B, // The RHS matrix 00937 int & n, // The column length of X 00938 int & m // The row length of X 00939 ) // Returns 0 if not solvable, 1 if solvable 00940 { 00941 n = A.Rmaxindex() - A.Rminindex(); 00942 m = B.Rmaxindex() - B.Rminindex(); 00943 00944 if((A.Lmaxindex() - A.Lminindex()) != n) 00945 // Oops! then A is not square 00946 return 0; 00947 00948 else if((n < 0)||(m < 0)) 00949 // Oops! then either A or B is empty 00950 return 0; 00951 00952 else if ((B.Lminindex() != A.Lminindex())||(B.Lmaxindex() != A.Lmaxindex())) 00953 // Oops! then A and B are not compatible 00954 return 0; 00955 00956 else { 00957 // all tests pass; so far so good 00958 n += 1; m += 1; // so they are proper lengths, rather than differences 00959 return 1; 00960 } 00961 } 00962 00963 // copies A and B into the previously-sized C so that C is A|B. 00964 // C must be properly sized and have Index_C in both dimensions 00965 static void augment(real_matrix & C, 00966 const real_matrix & A, 00967 const real_matrix & B 00968 ) 00969 { 00970 int n = C.Lsize; 00971 int m = C.Rsize - n; 00972 int ALmin = A.Lminindex(); 00973 int ARmin = A.Rminindex(); 00974 int BLmin = ALmin; 00975 int BRmin = B.Rminindex(); 00976 00977 for (int i = 0; i < n; ++i) { 00978 Acopy(C[i], A[i+ALmin]+ARmin, n); 00979 Acopy(C[i]+n, B[i+BLmin]+BRmin, m); 00980 } 00981 } 00982 00983 // scale the rows of C if necessary in preparation for solving. 00984 // right now (11/16) scale() always scales each row of C by the sum 00985 // of the magnitude squareds of the elements of A in that row. 00986 static void scale(real_matrix & C) 00987 { 00988 int n = C.Lsize; 00989 int m = C.Rsize; 00990 int i,j; 00991 double norm; 00992 double *d; 00993 00994 for(i = 0; i < n; ++i) { 00995 d = C[i]; 00996 for(j = 0, norm = 0; j < n; ++j) norm += ::norm(d[j]); 00997 if (norm > 0) Ascale(d, 1/norm, m); 00998 } 00999 } 01000 01001 // performs gaussian elimination of the augmented matrix C, with 01002 // partial pivoting. Does not back-substitute. Returns 0 if C 01003 // represents a singular system, otherwise returns 1 01004 static int triangle(real_matrix & C) 01005 { 01006 int n = C.Lsize; // number of equations 01007 int m = C.Rsize; // number of variables + number of RHS's 01008 int i, j, len; // i: current equation; j: indexes eqn's below i 01009 double *d, *f; // *d: diagonal element in eqn i; *f: elements below it 01010 01011 for (i = 0; i < n; ++i) { 01012 if ( ! pivot(i,C)) return 0; // pivot; return 0 if C is singular 01013 len = m - i - 1; // count of elements to be manipulated 01014 d = C[i]+i; // points to C[i][i] 01015 Ascale(d+1, 1/(*d), len); // put a 1 on the diagonal at [i][i] 01016 for (j = i+1; j < n; ++j) { 01017 f = C[j]+i; // points to C[j][i] 01018 if ( (*f) != 0.0 ) // don't bother if it's already a 0 01019 Ascalesub(f+1, d+1, (*f), len); // eliminate C[j][i] 01020 } 01021 } 01022 01023 return 1; 01024 } 01025 01026 // pivot row i of C with the rows following it. Returns 0 if a pivot 01027 // != 0 cannot be found (so C is singular), else returns 1. 01028 // (used by triangle()) 01029 static int pivot(int i, real_matrix & C) 01030 { 01031 int n = C.Lsize; 01032 double val, test; // val: largest norm seen so far in column i 01033 int j, pivot; // j: index; pivot: row # with the largest val 01034 01035 for (j = i, val = 0, pivot = -1; j < n; j++) { 01036 test = norm(C[j][i]); 01037 if (test > val) { 01038 val = test; pivot = j; 01039 } 01040 } 01041 01042 if (pivot == -1) 01043 return 0; // no nonzero pivots, so C is singular 01044 else if (pivot != i) { 01045 C.rowswap(i,pivot); 01046 return 1; 01047 } 01048 else return 1; 01049 } 01050 01051 // performs back-substitution in the solvable system C, writing the 01052 // results into the former locations of the RHS elements 01053 static void backsub(real_matrix & C) 01054 { 01055 int n = C.Lsize; // size of coefficient matrix 01056 int m = C.Rsize - n; // number of RHS vectors 01057 int i, j; // i: current equation; j: following equations 01058 double *xi, *xj; // xi: RHS's of eqn i; xj: RHS's of eqn j 01059 01060 for (i = n-2; i >= 0; --i) { 01061 xi = C[i]+n; 01062 for(j = i+1; j < n; ++j) { 01063 xj = C[j]+n; 01064 Ascalesub(xi, xj, C[i][j], m); 01065 } 01066 } 01067 } 01068 01069 // transcribes the results in C into the proper locations in X 01070 static void copyresult(real_matrix & X, const real_matrix & C) 01071 { 01072 int n = C.Lsize; // number of rows in X, and offset in C 01073 int m = C.Rsize - n; // number of columns in X 01074 int XLmin = X.Lminindex(); // offset from 0 to first row index of X 01075 int XRmin = X.Rminindex(); // offset from 0 to first column index of X 01076 01077 for (int i = 0; i < n; ++i) 01078 Acopy(X[i+XLmin]+XRmin, C[i]+n, m); 01079 } 01080 01081 // ======================================================================== 01082 // Complex Version: 01083 01084 // Solves AX == B and returns X. If it's unable to solve the system, 01085 // then X will be empty. 01086 complex_matrix solve(const complex_matrix & A, const complex_matrix & B); 01087 01088 complex_vector solve(const complex_matrix & A, const complex_vector & b) 01089 { 01090 return col(1, solve(A, complex_matrix(b))); 01091 } 01092 01093 // checks sizes of A and B in AX == B for solvability, 01094 // and puts lengths of X into n and m 01095 static int sizecheck( 01096 const complex_matrix & A, // The coefficient matrix 01097 const complex_matrix & B, // The RHS matrix 01098 int & n, // The column length of X 01099 int & m // The row length of X 01100 ); // Returns 0 if not solvable, 1 if solvable 01101 01102 // copies A and B into the previously-sized C so that C is A|B. 01103 // C must be properly sized and have Index_C in both dimensions 01104 static void augment(complex_matrix & C, 01105 const complex_matrix & A, 01106 const complex_matrix & B 01107 ); 01108 01109 // scale the rows of C if necessary in preparation for solving 01110 static void scale(complex_matrix & C); 01111 01112 // performs gaussian elimination of the augmented matrix C, with 01113 // partial pivoting. Does not back-substitute. Returns 0 if C 01114 // represents a singular system, otherwise returns 1 01115 static int triangle(complex_matrix & C); 01116 01117 // performs back-substitution in the solvable system C, writing the 01118 // results into the former locations of the RHS elements 01119 static void backsub(complex_matrix & C); 01120 01121 // transcribes the results in C into the proper locations in X 01122 static void copyresult(complex_matrix & X, const complex_matrix & C); 01123 01124 // pivot row i of C with the rows following it. Returns 0 if a pivot 01125 // != 0 cannot be found (so C is singular), else returns 1. 01126 // (used by triangle()) 01127 static int pivot(int i, complex_matrix & C); 01128 01129 // ------------------------------------------------------------------------ 01130 // the solver definitions: 01131 01132 // Solves AX == B and returns X. If it's unable to solve the system, 01133 // then X will be empty. 01134 complex_matrix solve(const complex_matrix & A, const complex_matrix & B) 01135 { 01136 complex_matrix X(0,0,Index_1,Index_1); // the solution (empty for now) 01137 int n, m; // the column length and row length of X 01138 01139 // Calculate n and m and check compatibility of A and B: 01140 if ( ! sizecheck(A, B, n, m) ) 01141 // sizecheck returns 0 if the geometries of A and B aren't o.k. 01142 return X; // failure: returns the empty X 01143 01144 // Passed sizecheck(). Make the augmented matrix C from A and B: 01145 complex_matrix C(n, n+m, Index_C, Index_C); 01146 augment(C, A, B); 01147 scale(C); // individually scales each row to improve solver accuracy 01148 01149 // Perform the Gaussian Elimination, with X values replacing B in C: 01150 if ( ! triangle(C)) 01151 // triangle() returns 0 if A is singular, so system can't be solved 01152 return X; // failure: returns the empty X 01153 backsub(C); 01154 01155 // Now resize X and copy the results into it, then return: 01156 X.reallocate(A.Rsize, B.Rsize, A.Rmode, B.Rmode); 01157 X.Lmaxindex(A.Rmaxindex()); 01158 X.Rmaxindex(B.Rmaxindex()); 01159 copyresult(X, C); 01160 return X; 01161 } 01162 01163 // Uses solve() to find the inverse of a matrix. If the inverse doesn't 01164 // exist, then the returned matrix will be empty. Note: the index modes and 01165 // valid index ranges of A must be the same in both dimensions for an 01166 // inverse to exist (A is square). 01167 complex_matrix inverse(const complex_matrix & A) 01168 { 01169 complex_matrix B(0); // will become the RHS for solve() 01170 01171 if ((A.Rmode == A.Lmode)&&(A.Rmaxindex() == A.Lmaxindex())) { 01172 // then A may be invertible, so set up the RHS for solve() 01173 B.resize(A); 01174 B.diagonal(1.0); 01175 } 01176 // if the above if failed, then the RHS is empty, and so will be the 01177 // returned matrix from solve() 01178 return solve(A,B); 01179 } 01180 01181 // checks sizes of A and B in AX == B for solvability, 01182 // and puts lengths of X into n and m 01183 static int sizecheck( 01184 const complex_matrix & A, // The coefficient matrix 01185 const complex_matrix & B, // The RHS matrix 01186 int & n, // The column length of X 01187 int & m // The row length of X 01188 ) // Returns 0 if not solvable, 1 if solvable 01189 { 01190 n = A.Rmaxindex() - A.Rminindex(); 01191 m = B.Rmaxindex() - B.Rminindex(); 01192 01193 if((A.Lmaxindex() - A.Lminindex()) != n) 01194 // Oops! then A is not square 01195 return 0; 01196 01197 else if((n < 0)||(m < 0)) 01198 // Oops! then either A or B is empty 01199 return 0; 01200 01201 else if ((B.Lminindex() != A.Lminindex())||(B.Lmaxindex() != A.Lmaxindex())) 01202 // Oops! then A and B are not compatible 01203 return 0; 01204 01205 else { 01206 // all tests pass; so far so good 01207 n += 1; m += 1; // so they are proper lengths, rather than differences 01208 return 1; 01209 } 01210 } 01211 01212 // copies A and B into the previously-sized C so that C is A|B. 01213 // C must be properly sized and have Index_C in both dimensions 01214 static void augment(complex_matrix & C, 01215 const complex_matrix & A, 01216 const complex_matrix & B 01217 ) 01218 { 01219 int n = C.Lsize; 01220 int m = C.Rsize - n; 01221 int ALmin = A.Lminindex(); 01222 int ARmin = A.Rminindex(); 01223 int BLmin = ALmin; 01224 int BRmin = B.Rminindex(); 01225 01226 for (int i = 0; i < n; ++i) { 01227 Acopy(C[i], A[i+ALmin]+ARmin, n); 01228 Acopy(C[i]+n, B[i+BLmin]+BRmin, m); 01229 } 01230 } 01231 01232 // scale the rows of C if necessary in preparation for solving. 01233 // right now (11/16) scale() always scales each row of C by the sum 01234 // of the magnitude squareds of the elements of A in that row. 01235 static void scale(complex_matrix & C) 01236 { 01237 int n = C.Lsize; 01238 int m = C.Rsize; 01239 int i,j; 01240 double norm; 01241 Complex *d; 01242 01243 for(i = 0; i < n; ++i) { 01244 d = C[i]; 01245 for(j = 0, norm = 0; j < n; ++j) norm += ::norm(d[j]); 01246 if (norm > 0) Ascale(d, 1/norm, m); 01247 } 01248 } 01249 01250 // performs gaussian elimination of the augmented matrix C, with 01251 // partial pivoting. Does not back-substitute. Returns 0 if C 01252 // represents a singular system, otherwise returns 1 01253 static int triangle(complex_matrix & C) 01254 { 01255 int n = C.Lsize; // number of equations 01256 int m = C.Rsize; // number of variables + number of RHS's 01257 int i, j, len; // i: current equation; j: indexes eqn's below i 01258 Complex *d, *f; // *d: diagonal element in eqn i; *f: elements below it 01259 01260 for (i = 0; i < n; ++i) { 01261 if ( ! pivot(i,C)) return 0; // pivot; return 0 if C is singular 01262 len = m - i - 1; // count of elements to be manipulated 01263 d = C[i]+i; // points to C[i][i] 01264 Ascale(d+1, 1/(*d), len); // put a 1 on the diagonal at [i][i] 01265 for (j = i+1; j < n; ++j) { 01266 f = C[j]+i; // points to C[j][i] 01267 if ( (*f) != 0.0 ) // don't bother if it's already a 0 01268 Ascalesub(f+1, d+1, (*f), len); // eliminate C[j][i] 01269 } 01270 } 01271 01272 return 1; 01273 } 01274 01275 // pivot row i of C with the rows following it. Returns 0 if a pivot 01276 // != 0 cannot be found (so C is singular), else returns 1. 01277 // (used by triangle()) 01278 static int pivot(int i, complex_matrix & C) 01279 { 01280 int n = C.Lsize; 01281 double val, test; // val: largest norm seen so far in column i 01282 int j, pivot; // j: index; pivot: row # with the largest val 01283 01284 for (j = i, val = 0, pivot = -1; j < n; j++) { 01285 test = norm(C[j][i]); 01286 if (test > val) { 01287 val = test; pivot = j; 01288 } 01289 } 01290 01291 if (pivot == -1) 01292 return 0; // no nonzero pivots, so C is singular 01293 else if (pivot != i) { 01294 C.rowswap(i,pivot); 01295 return 1; 01296 } 01297 else return 1; 01298 } 01299 01300 // performs back-substitution in the solvable system C, writing the 01301 // results into the former locations of the RHS elements 01302 static void backsub(complex_matrix & C) 01303 { 01304 int n = C.Lsize; // size of coefficient matrix 01305 int m = C.Rsize - n; // number of RHS vectors 01306 int i, j; // i: current equation; j: following equations 01307 Complex *xi, *xj; // xi: RHS's of eqn i; xj: RHS's of eqn j 01308 01309 for (i = n-2; i >= 0; --i) { 01310 xi = C[i]+n; 01311 for(j = i+1; j < n; ++j) { 01312 xj = C[j]+n; 01313 Ascalesub(xi, xj, C[i][j], m); 01314 } 01315 } 01316 } 01317 01318 // transcribes the results in C into the proper locations in X 01319 static void copyresult(complex_matrix & X, const complex_matrix & C) 01320 { 01321 int n = C.Lsize; // number of rows in X, and offset in C 01322 int m = C.Rsize - n; // number of columns in X 01323 int XLmin = X.Lminindex(); // offset from 0 to first row index of X 01324 int XRmin = X.Rminindex(); // offset from 0 to first column index of X 01325 01326 for (int i = 0; i < n; ++i) 01327 Acopy(X[i+XLmin]+XRmin, C[i]+n, m); 01328 } 01329 01330 // ************************************************************************ 01331 // Special Fast Square Matrix Operations: 01332 01333 void IplusM(Matrix & U, double s, const Matrix & V) 01334 { 01335 register int i,j; 01336 register int max = V.Lmaxindex(); 01337 for (i = V.Lminindex(); i <= max; ++i) { 01338 U[i][i] = s + V[i][i]; 01339 for (j = i+1; j <= max; ++j) { 01340 U[i][j] = V[i][j]; 01341 U[j][i] = V[j][i]; 01342 } 01343 } 01344 } 01345 01346 void IminusM(Matrix & U, double s, const Matrix & V) 01347 { 01348 register int i,j; 01349 register int max = V.Lmaxindex(); 01350 for (i = V.Lminindex(); i <= max; ++i) { 01351 U[i][i] = s - V[i][i]; 01352 for (j = i+1; j <= max; ++j) { 01353 U[i][j] = -V[i][j]; 01354 U[j][i] = -V[j][i]; 01355 } 01356 } 01357 } 01358 01359 void MMdagger(Matrix & U, const Matrix & V) 01360 { 01361 int min = V.Lminindex(), max = V.Lmaxindex(); 01362 int len = max - min + 1; len = (len < 0) ? 0 : len; // length of a row 01363 const complex *ai, *aj; 01364 for (int i = min; i <= max; ++i) { 01365 ai = & V[i][min]; 01366 U[i][i] = Adot(ai,ai,len); 01367 for (int j = i + 1; j <= max; ++j) { 01368 aj = & V[j][min]; 01369 U[j][i] = conj( U[i][j] = Adot(aj,ai,len) ); 01370 } 01371 } 01372 } 01373 01374 void MAMdagger(Matrix & U, const Matrix & V, const Matrix & W) 01375 { 01376 int i, j, k; 01377 int min = V.Lminindex(), max = V.Lmaxindex(); 01378 int len = max - min + 1; len = (len < 0) ? 0 : len; // length of a row 01379 const complex *pVi, *pVj; 01380 complex sum; 01381 for (i = min; i <= max; ++i) { 01382 pVi = & V[i][min]; 01383 for (j = min; j <= max; ++j) { 01384 pVj = (& V[j][min]) - 1; 01385 sum = 0.0; 01386 for (k = min; k <= max; ++k) 01387 sum += (*(++pVj))*Adot(pVi, &W[k][min], len); 01388 U[j][i] = sum; 01389 } 01390 } 01391 }
Please direct comments and corrections to
supermix@submm.caltech.edu
Go to the supermix home page
Generated by
1.2.7