Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

matmath.cc

Go to the documentation of this file.
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 doxygen1.2.7