00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036
00037
00038
00039 #include <cfloat>
00040 #include <cmath>
00041 #include <cstdlib>
00042
00043 #include "SprMatrix.hh"
00044 #include "SprSymMatrix.hh"
00045 #include "SprVector.hh"
00046
00047
00048
00049 #define SIMPLE_UOP(OPER) \
00050 register mIter a=m.begin(); \
00051 register mIter e=m.end(); \
00052 for(;a!=e; a++) (*a) OPER t;
00053
00054 #define SIMPLE_BOP(OPER) \
00055 register SprMatrix::mIter a=m.begin(); \
00056 register SprMatrix::mcIter b=m2.m.begin(); \
00057 register SprMatrix::mIter e=m.end(); \
00058 for(;a!=e; a++, b++) (*a) OPER (*b);
00059
00060 #define SIMPLE_TOP(OPER) \
00061 register SprMatrix::mcIter a=m1.m.begin(); \
00062 register SprMatrix::mcIter b=m2.m.begin(); \
00063 register SprMatrix::mIter t=mret.m.begin(); \
00064 register SprMatrix::mcIter e=m1.m.end(); \
00065 for(;a!=e; a++, b++, t++) (*t) = (*a) OPER (*b);
00066
00067
00068
00069 #define CHK_DIM_2(r1,r2,c1,c2,fun) \
00070 if (r1!=r2 || c1!=c2) { \
00071 SprGenMatrix::error("Range error in Matrix function " #fun "(1)."); \
00072 }
00073
00074 #define CHK_DIM_1(c1,r2,fun) \
00075 if (c1!=r2) { \
00076 SprGenMatrix::error("Range error in Matrix function " #fun "(2)."); \
00077 }
00078
00079
00080
00081 SprMatrix::SprMatrix(int p,int q)
00082 : m(p*q), nrow(p), ncol(q)
00083 {
00084 size = nrow * ncol;
00085 }
00086
00087 SprMatrix::SprMatrix(int p,int q,int init)
00088 : m(p*q), nrow(p), ncol(q)
00089 {
00090 size = nrow * ncol;
00091
00092 if (size > 0) {
00093 switch(init)
00094 {
00095 case 0:
00096 break;
00097
00098 case 1:
00099 {
00100 if ( ncol == nrow ) {
00101 mIter a = m.begin();
00102 mIter b = m.end();
00103 for( ; a<b; a+=(ncol+1)) *a = 1.0;
00104 } else {
00105 error("Invalid dimension in SprMatrix(int,int,1).");
00106 }
00107 break;
00108 }
00109 default:
00110 error("Matrix: initialization must be either 0 or 1.");
00111 }
00112 }
00113 }
00114
00115
00116
00117
00118 SprMatrix::~SprMatrix() {
00119 }
00120
00121 SprMatrix::SprMatrix(const SprMatrix &m1)
00122 : m(m1.size), nrow(m1.nrow), ncol(m1.ncol), size(m1.size)
00123 {
00124 m = m1.m;
00125
00126 }
00127
00128 SprMatrix::SprMatrix(const SprSymMatrix &m1)
00129 : m(m1.nrow*m1.nrow), nrow(m1.nrow), ncol(m1.nrow)
00130 {
00131 size = nrow * ncol;
00132
00133 int n = ncol;
00134 mcIter sjk = m1.m.begin();
00135 mIter m1j = m.begin();
00136 mIter mj = m.begin();
00137
00138 for(int j=1;j<=nrow;j++) {
00139 mIter mjk = mj;
00140 mIter mkj = m1j;
00141 for(int k=1;k<=j;k++) {
00142 *(mjk++) = *sjk;
00143 if(j!=k) *mkj = *sjk;
00144 sjk++;
00145 mkj += n;
00146 }
00147 mj += n;
00148 m1j++;
00149 }
00150 }
00151
00152 SprMatrix::SprMatrix(const SprVector &m1)
00153 : m(m1.nrow), nrow(m1.nrow), ncol(1)
00154 {
00155
00156 size = nrow;
00157 m = m1.m;
00158 }
00159
00160
00161
00162
00163
00164
00165
00166
00167 SprMatrix SprMatrix::sub(int min_row, int max_row,
00168 int min_col,int max_col) const
00169 {
00170 SprMatrix mret(max_row-min_row+1,max_col-min_col+1);
00171 if(max_row > num_row() || max_col >num_col())
00172 error("SprMatrix::sub: Index out of range");
00173 mIter a = mret.m.begin();
00174 int nc = num_col();
00175 mcIter b1 = m.begin() + (min_row - 1) * nc + min_col - 1;
00176
00177 for(int irow=1; irow<=mret.num_row(); irow++) {
00178 mcIter brc = b1;
00179 for(int icol=1; icol<=mret.num_col(); icol++) {
00180 *(a++) = *(brc++);
00181 }
00182 b1 += nc;
00183 }
00184 return mret;
00185 }
00186
00187 void SprMatrix::sub(int row,int col,const SprMatrix &m1)
00188 {
00189 if(row <1 || row+m1.num_row()-1 > num_row() ||
00190 col <1 || col+m1.num_col()-1 > num_col() )
00191 error("SprMatrix::sub: Index out of range");
00192 mcIter a = m1.m.begin();
00193 int nc = num_col();
00194 mIter b1 = m.begin() + (row - 1) * nc + col - 1;
00195
00196 for(int irow=1; irow<=m1.num_row(); irow++) {
00197 mIter brc = b1;
00198 for(int icol=1; icol<=m1.num_col(); icol++) {
00199 *(brc++) = *(a++);
00200 }
00201 b1 += nc;
00202 }
00203 }
00204
00205
00206
00207
00208
00209 SprMatrix dsum(const SprMatrix &m1, const SprMatrix &m2)
00210 {
00211 SprMatrix mret(m1.num_row() + m2.num_row(), m1.num_col() + m2.num_col(),
00212 0);
00213 mret.sub(1,1,m1);
00214 mret.sub(m1.num_row()+1,m1.num_col()+1,m2);
00215 return mret;
00216 }
00217
00218
00219
00220
00221
00222 SprMatrix SprMatrix::operator- () const
00223 {
00224 SprMatrix m2(nrow, ncol);
00225 register mcIter a=m.begin();
00226 register mIter b=m2.m.begin();
00227 register mcIter e=m.end();
00228 for(;a<e; a++, b++) (*b) = -(*a);
00229 return m2;
00230 }
00231
00232
00233
00234 SprMatrix operator+(const SprMatrix &m1,const SprMatrix &m2)
00235 {
00236 SprMatrix mret(m1.nrow, m1.ncol);
00237 CHK_DIM_2(m1.num_row(),m2.num_row(), m1.num_col(),m2.num_col(),+);
00238 SIMPLE_TOP(+)
00239 return mret;
00240 }
00241
00242
00243
00244
00245
00246 SprMatrix operator-(const SprMatrix &m1,const SprMatrix &m2)
00247 {
00248 SprMatrix mret(m1.num_row(), m1.num_col());
00249 CHK_DIM_2(m1.num_row(),m2.num_row(),
00250 m1.num_col(),m2.num_col(),-);
00251 SIMPLE_TOP(-)
00252 return mret;
00253 }
00254
00255
00256
00257
00258
00259
00260 SprMatrix operator/(
00261 const SprMatrix &m1,double t)
00262 {
00263 SprMatrix mret(m1);
00264 mret /= t;
00265 return mret;
00266 }
00267
00268 SprMatrix operator*(const SprMatrix &m1,double t)
00269 {
00270 SprMatrix mret(m1);
00271 mret *= t;
00272 return mret;
00273 }
00274
00275 SprMatrix operator*(double t,const SprMatrix &m1)
00276 {
00277 SprMatrix mret(m1);
00278 mret *= t;
00279 return mret;
00280 }
00281
00282 SprMatrix operator*(const SprMatrix &m1,const SprMatrix &m2)
00283 {
00284
00285 SprMatrix mret(m1.nrow,m2.ncol,0);
00286 CHK_DIM_1(m1.ncol,m2.nrow,*);
00287
00288 int m1cols = m1.ncol;
00289 int m2cols = m2.ncol;
00290
00291 for (int i=0; i<m1.nrow; i++)
00292 {
00293 for (int j=0; j<m1cols; j++)
00294 {
00295 register double temp = m1.m[i*m1cols+j];
00296 register SprMatrix::mIter pt = mret.m.begin() + i*m2cols;
00297
00298
00299 register SprMatrix::mcIter pb = m2.m.begin() + m2cols*j;
00300 const SprMatrix::mcIter pblast = pb + m2cols;
00301 while (pb < pblast)
00302 {
00303 (*pt) += temp * (*pb);
00304 pb++;
00305 pt++;
00306 }
00307 }
00308 }
00309
00310 return mret;
00311 }
00312
00313
00314
00315
00316
00317 SprMatrix & SprMatrix::operator+=(const SprMatrix &m2)
00318 {
00319 CHK_DIM_2(num_row(),m2.num_row(),num_col(),m2.num_col(),+=);
00320 SIMPLE_BOP(+=)
00321 return (*this);
00322 }
00323
00324 SprMatrix & SprMatrix::operator-=(const SprMatrix &m2)
00325 {
00326 CHK_DIM_2(num_row(),m2.num_row(),num_col(),m2.num_col(),-=);
00327 SIMPLE_BOP(-=)
00328 return (*this);
00329 }
00330
00331 SprMatrix & SprMatrix::operator/=(double t)
00332 {
00333 SIMPLE_UOP(/=)
00334 return (*this);
00335 }
00336
00337 SprMatrix & SprMatrix::operator*=(double t)
00338 {
00339 SIMPLE_UOP(*=)
00340 return (*this);
00341 }
00342
00343 SprMatrix & SprMatrix::operator=(const SprMatrix &m1)
00344 {
00345 if(m1.nrow*m1.ncol != size)
00346 {
00347 size = m1.nrow * m1.ncol;
00348 m.resize(size);
00349 }
00350 nrow = m1.nrow;
00351 ncol = m1.ncol;
00352 m = m1.m;
00353 return (*this);
00354 }
00355
00356
00357
00358
00359
00360
00361 std::ostream& operator<<(std::ostream &s, const SprMatrix &q)
00362 {
00363 s << "\n";
00364
00365 int width;
00366 if(s.flags() & std::ios::fixed)
00367 width = s.precision()+3;
00368 else
00369 width = s.precision()+7;
00370 for(int irow = 1; irow<= q.num_row(); irow++)
00371 {
00372 for(int icol = 1; icol <= q.num_col(); icol++)
00373 {
00374 s.width(width);
00375 s << q(irow,icol) << " ";
00376 }
00377 s << std::endl;
00378 }
00379 return s;
00380 }
00381
00382 SprMatrix SprMatrix::T() const
00383 {
00384 SprMatrix mret(ncol,nrow);
00385 register mcIter pl = m.end();
00386 register mcIter pme = m.begin();
00387 register mIter pt = mret.m.begin();
00388 register mIter ptl = mret.m.end();
00389 for (; pme < pl; pme++, pt+=nrow)
00390 {
00391 if (pt >= ptl) pt -= (size-1);
00392 (*pt) = (*pme);
00393 }
00394 return mret;
00395 }
00396
00397 SprMatrix SprMatrix::apply(double (*f)(double, int, int)) const
00398 {
00399 SprMatrix mret(num_row(),num_col());
00400 mcIter a = m.begin();
00401 mIter b = mret.m.begin();
00402 for(int ir=1;ir<=num_row();ir++) {
00403 for(int ic=1;ic<=num_col();ic++) {
00404 *(b++) = (*f)(*(a++), ir, ic);
00405 }
00406 }
00407 return mret;
00408 }
00409
00410 int SprMatrix::dfinv_matrix(int *ir) {
00411 if (num_col()!=num_row())
00412 error("dfinv_matrix: Matrix is not NxN");
00413 register int n = num_col();
00414 if (n==1) return 0;
00415
00416 double s31, s32;
00417 register double s33, s34;
00418
00419 mIter m11 = m.begin();
00420 mIter m12 = m11 + 1;
00421 mIter m21 = m11 + n;
00422 mIter m22 = m12 + n;
00423 *m21 = -(*m22) * (*m11) * (*m21);
00424 *m12 = -(*m12);
00425 if (n>2) {
00426 mIter mi = m.begin() + 2 * n;
00427 mIter mii= m.begin() + 2 * n + 2;
00428 mIter mimim = m.begin() + n + 1;
00429 for (int i=3;i<=n;i++) {
00430 int im2 = i - 2;
00431 mIter mj = m.begin();
00432 mIter mji = mj + i - 1;
00433 mIter mij = mi;
00434 for (int j=1;j<=im2;j++) {
00435 s31 = 0.0;
00436 s32 = *mji;
00437 mIter mkj = mj + j - 1;
00438 mIter mik = mi + j - 1;
00439 mIter mjkp = mj + j;
00440 mIter mkpi = mj + n + i - 1;
00441 for (int k=j;k<=im2;k++) {
00442 s31 += (*mkj) * (*(mik++));
00443 s32 += (*(mjkp++)) * (*mkpi);
00444 mkj += n;
00445 mkpi += n;
00446 }
00447 *mij = -(*mii) * (((*(mij-n)))*( (*(mii-1)))+(s31));
00448 *mji = -s32;
00449 mj += n;
00450 mji += n;
00451 mij++;
00452 }
00453 *(mii-1) = -(*mii) * (*mimim) * (*(mii-1));
00454 *(mimim+1) = -(*(mimim+1));
00455 mi += n;
00456 mimim += (n+1);
00457 mii += (n+1);
00458 }
00459 }
00460 mIter mi = m.begin();
00461 mIter mii = m.begin();
00462 for (int i=1;i<n;i++) {
00463 int ni = n - i;
00464 mIter mij = mi;
00465 int j;
00466 for (j=1; j<=i;j++) {
00467 s33 = *mij;
00468 register mIter mikj = mi + n + j - 1;
00469 register mIter miik = mii + 1;
00470 mIter min_end = mi + n;
00471 for (;miik<min_end;) {
00472 s33 += (*mikj) * (*(miik++));
00473 mikj += n;
00474 }
00475 *(mij++) = s33;
00476 }
00477 for (j=1;j<=ni;j++) {
00478 s34 = 0.0;
00479 mIter miik = mii + j;
00480 mIter mikij = mii + j * n + j;
00481 for (int k=j;k<=ni;k++) {
00482 s34 += *mikij * (*(miik++));
00483 mikij += n;
00484 }
00485 *(mii+j) = s34;
00486 }
00487 mi += n;
00488 mii += (n+1);
00489 }
00490 int nxch = ir[n];
00491 if (nxch==0) return 0;
00492 for (int mm=1;mm<=nxch;mm++) {
00493 int k = nxch - mm + 1;
00494 int ij = ir[k];
00495 int i = ij >> 12;
00496 int j = ij%4096;
00497 mIter mki = m.begin() + i - 1;
00498 mIter mkj = m.begin() + j - 1;
00499 for (k=1; k<=n;k++) {
00500
00501
00502 double ti = *mki;
00503 *mki = *mkj;
00504 *mkj = ti;
00505 mki += n;
00506 mkj += n;
00507 }
00508 }
00509 return 0;
00510 }
00511
00512 int SprMatrix::dfact_matrix(double &det, int *ir) {
00513 if (ncol!=nrow)
00514 error("dfact_matrix: Matrix is not NxN");
00515
00516 int ifail, jfail;
00517 register int n = ncol;
00518
00519 double tf;
00520 double g1 = 1.0e-19, g2 = 1.0e19;
00521
00522 double p, q, t;
00523 double s11, s12;
00524
00525 double epsilon = 8*DBL_EPSILON;
00526
00527
00528
00529
00530 int normal = 0, imposs = -1;
00531 int jrange = 0, jover = 1, junder = -1;
00532 ifail = normal;
00533 jfail = jrange;
00534 int nxch = 0;
00535 det = 1.0;
00536 mIter mj = m.begin();
00537 mIter mjj = mj;
00538 for (int j=1;j<=n;j++) {
00539 int k = j;
00540 p = (fabs(*mjj));
00541 if (j!=n) {
00542 mIter mij = mj + n + j - 1;
00543 for (int i=j+1;i<=n;i++) {
00544 q = (fabs(*(mij)));
00545 if (q > p) {
00546 k = i;
00547 p = q;
00548 }
00549 mij += n;
00550 }
00551 if (k==j) {
00552 if (p <= epsilon) {
00553 det = 0;
00554 ifail = imposs;
00555 jfail = jrange;
00556 return ifail;
00557 }
00558 det = -det;
00559
00560 }
00561 mIter mjl = mj;
00562 mIter mkl = m.begin() + (k-1)*n;
00563 for (int l=1;l<=n;l++) {
00564 tf = *mjl;
00565 *(mjl++) = *mkl;
00566 *(mkl++) = tf;
00567 }
00568 nxch = nxch + 1;
00569 ir[nxch] = (((j)<<12)+(k));
00570 } else {
00571 if (p <= epsilon) {
00572 det = 0.0;
00573 ifail = imposs;
00574 jfail = jrange;
00575 return ifail;
00576 }
00577 }
00578 det *= *mjj;
00579 *mjj = 1.0 / *mjj;
00580 t = (fabs(det));
00581 if (t < g1) {
00582 det = 0.0;
00583 if (jfail == jrange) jfail = junder;
00584 } else if (t > g2) {
00585 det = 1.0;
00586 if (jfail==jrange) jfail = jover;
00587 }
00588 if (j!=n) {
00589 mIter mk = mj + n;
00590 mIter mkjp = mk + j;
00591 mIter mjk = mj + j;
00592 for (k=j+1;k<=n;k++) {
00593 s11 = - (*mjk);
00594 s12 = - (*mkjp);
00595 if (j!=1) {
00596 mIter mik = m.begin() + k - 1;
00597 mIter mijp = m.begin() + j;
00598 mIter mki = mk;
00599 mIter mji = mj;
00600 for (int i=1;i<j;i++) {
00601 s11 += (*mik) * (*(mji++));
00602 s12 += (*mijp) * (*(mki++));
00603 mik += n;
00604 mijp += n;
00605 }
00606 }
00607 *(mjk++) = -s11 * (*mjj);
00608 *(mkjp) = -(((*(mjj+1)))*((*(mkjp-1)))+(s12));
00609 mk += n;
00610 mkjp += n;
00611 }
00612 }
00613 mj += n;
00614 mjj += (n+1);
00615 }
00616 if (nxch%2==1) det = -det;
00617 if (jfail !=jrange) det = 0.0;
00618 ir[n] = nxch;
00619 return 0;
00620 }
00621
00622
00623
00624
00625 double SprMatrix::determinant() const {
00626 static int max_array = 20;
00627 static int *ir = new int [max_array+1];
00628 if(ncol != nrow)
00629 error("SprMatrix::determinant: Matrix is not NxN");
00630 if (ncol > max_array) {
00631 delete [] ir;
00632 max_array = nrow;
00633 ir = new int [max_array+1];
00634 }
00635 double det;
00636 SprMatrix mt(*this);
00637 int i = mt.dfact_matrix(det, ir);
00638 if(i==0) return det;
00639 return 0;
00640 }
00641
00642 double SprMatrix::trace() const {
00643 double t = 0.0;
00644 for (mcIter d = m.begin(); d < m.end(); d += (ncol+1) )
00645 t += *d;
00646 return t;
00647 }
00648
00649
00650 void SprMatrix::row_house(const SprMatrix &v,
00651 int row,int col,int row_start,int col_start)
00652 {
00653 double normsq=0;
00654 int end = row_start+this->num_row()-row;
00655 for (int i=row_start; i<=end; i++)
00656 normsq += v(i,col)*v(i,col);
00657
00658 if (normsq !=0)
00659 this->row_house(v,normsq,row,col,row_start,col_start);
00660 }
00661
00662
00663 void SprMatrix::row_house(const SprMatrix &v,
00664 double vnormsq,
00665 int row, int col, int row_start, int col_start) {
00666 double beta=-2/vnormsq;
00667
00668
00669 SprVector w(this->num_col()-col+1,0);
00670 int na = this->num_col();
00671 int nv = v.num_col();
00672 SprMatrix::mIter wptr = w.m.begin();
00673 SprMatrix::mIter arcb = this->m.begin() + (row-1) * na + (col-1);
00674 SprMatrix::mcIter vpcb = v.m.begin() + (row_start-1) * nv + (col_start-1);
00675 int c;
00676 for (c=col;c<=this->num_col();c++) {
00677 SprMatrix::mIter arc = arcb;
00678 SprMatrix::mcIter vpc = vpcb;
00679 for (int r=row;r<=this->num_row();r++) {
00680 (*wptr)+=(*arc)*(*vpc);
00681 arc += na;
00682 vpc += nv;
00683 }
00684 wptr++;
00685 arcb++;
00686 }
00687 w*=beta;
00688
00689 arcb = this->m.begin() + (row-1) * na + (col-1);
00690 SprMatrix::mcIter vpc = v.m.begin() + (row_start-1) * nv + (col_start-1);
00691 for (int r=row; r<=this->num_row();r++) {
00692 SprMatrix::mIter arc = arcb;
00693 SprMatrix::mIter wptr = w.m.begin();
00694 for (c=col;c<=this->num_col();c++) {
00695 (*(arc++))+=(*vpc)*(*(wptr++));
00696 }
00697 arcb += na;
00698 vpc += nv;
00699 }
00700 }
00701
00702
00703 void SprMatrix::givens(double a, double b, double *c, double *s)
00704 {
00705 if (b ==0) { *c=1; *s=0; }
00706 else {
00707 if (fabs(b)>fabs(a)) {
00708 double tau=-a/b;
00709 *s=1/sqrt(1+tau*tau);
00710 *c=(*s)*tau;
00711 } else {
00712 double tau=-b/a;
00713 *c=1/sqrt(1+tau*tau);
00714 *s=(*c)*tau;
00715 }
00716 }
00717 }
00718
00719
00720 void SprMatrix::col_givens(double c,double s,
00721 int k1, int k2, int row_min, int row_max) {
00722 if (row_max<=0) row_max = this->num_row();
00723 int n = this->num_col();
00724 SprMatrix::mIter Ajk1 = this->m.begin() + (row_min - 1) * n + k1 - 1;
00725 SprMatrix::mIter Ajk2 = this->m.begin() + (row_min - 1) * n + k2 - 1;
00726 for (int j=row_min;j<=row_max;j++) {
00727 double tau1=(*Ajk1); double tau2=(*Ajk2);
00728 (*Ajk1)=c*tau1-s*tau2;(*Ajk2)=s*tau1+c*tau2;
00729 Ajk1 += n;
00730 Ajk2 += n;
00731 }
00732 }
00733