// -*- C++ -*- // --------------------------------------------------------------------------- // // This file is a part of the CLHEP - a Class Library for High Energy Physics. // #ifdef GNUPRAGMA #pragma implementation #endif #include #include // for DBL_EPSILON #include #include #include "CLHEP/Matrix/defs.h" #include "CLHEP/Random/Random.h" #include "CLHEP/Matrix/Matrix.h" #include "CLHEP/Matrix/SymMatrix.h" #include "CLHEP/Matrix/DiagMatrix.h" #include "CLHEP/Matrix/Vector.h" #ifdef HEP_DEBUG_INLINE #include "CLHEP/Matrix/Matrix.icc" #endif namespace CLHEP { // Simple operation for all elements #define SIMPLE_UOP(OPER) \ register mIter a=m.begin(); \ register mIter e=m.end(); \ for(;a!=e; a++) (*a) OPER t; #define SIMPLE_BOP(OPER) \ register HepMatrix::mIter a=m.begin(); \ register HepMatrix::mcIter b=m2.m.begin(); \ register HepMatrix::mIter e=m.end(); \ for(;a!=e; a++, b++) (*a) OPER (*b); #define SIMPLE_TOP(OPER) \ register HepMatrix::mcIter a=m1.m.begin(); \ register HepMatrix::mcIter b=m2.m.begin(); \ register HepMatrix::mIter t=mret.m.begin(); \ register HepMatrix::mcIter e=m1.m.end(); \ for(;a!=e; a++, b++, t++) (*t) = (*a) OPER (*b); // Static functions. #define CHK_DIM_2(r1,r2,c1,c2,fun) \ if (r1!=r2 || c1!=c2) { \ HepGenMatrix::error("Range error in Matrix function " #fun "(1)."); \ } #define CHK_DIM_1(c1,r2,fun) \ if (c1!=r2) { \ HepGenMatrix::error("Range error in Matrix function " #fun "(2)."); \ } // Constructors. (Default constructors are inlined and in .icc file) HepMatrix::HepMatrix(int p,int q) : m(p*q), nrow(p), ncol(q) { size_ = nrow * ncol; } HepMatrix::HepMatrix(int p,int q,int init) : m(p*q), nrow(p), ncol(q) { size_ = nrow * ncol; if (size_ > 0) { switch(init) { case 0: break; case 1: { if ( ncol == nrow ) { mIter a = m.begin(); for( int step=0; step < size_; step+=(ncol+1) ) *(a+step) = 1.0; } else { error("Invalid dimension in HepMatrix(int,int,1)."); } break; } default: error("Matrix: initialization must be either 0 or 1."); } } } HepMatrix::HepMatrix(int p,int q, HepRandom &r) : m(p*q), nrow(p), ncol(q) { size_ = nrow * ncol; mIter a = m.begin(); mIter b = m.end(); for(; anum_row() || col<1 || col>num_col()) error("Range error in HepMatrix::operator()"); #endif return *(m.begin()+(row-1)*ncol+col-1); } const double & HepMatrix::operator()(int row, int col) const { #ifdef MATRIX_BOUND_CHECK if(row<1 || row>num_row() || col<1 || col>num_col()) error("Range error in HepMatrix::operator()"); #endif return *(m.begin()+(row-1)*ncol+col-1); } HepMatrix::HepMatrix(const HepSymMatrix &m1) : m(m1.nrow*m1.nrow), nrow(m1.nrow), ncol(m1.nrow) { size_ = nrow * ncol; mcIter sjk = m1.m.begin(); // j >= k for(int j=0; j!=nrow; ++j) { for(int k=0; k<=j; ++k) { m[j*ncol+k] = *sjk; // we could copy the diagonal element twice or check // doing the check may be a tiny bit faster, // so we choose that option for now if(k!=j) m[k*nrow+j] = *sjk; ++sjk; } } } HepMatrix::HepMatrix(const HepDiagMatrix &m1) : m(m1.nrow*m1.nrow), nrow(m1.nrow), ncol(m1.nrow) { size_ = nrow * ncol; int n = num_row(); mIter mrr; mcIter mr = m1.m.begin(); for(int r=0;r num_row() || max_col >num_col()) error("HepMatrix::sub: Index out of range"); mIter a = mret.m.begin(); int nc = num_col(); mcIter b1 = m.begin() + (min_row - 1) * nc + min_col - 1; int rowsize = mret.num_row(); for(int irow=1; irow<=rowsize; ++irow) { mcIter brc = b1; for(int icol=0; icol num_row() || col <1 || col+m1.num_col()-1 > num_col() ) error("HepMatrix::sub: Index out of range"); mcIter a = m1.m.begin(); int nc = num_col(); mIter b1 = m.begin() + (row - 1) * nc + col - 1; int rowsize = m1.num_row(); for(int irow=1; irow<=rowsize; ++irow) { mIter brc = b1; for(int icol=0; icol2) { mIter mimim = m11 + n + 1; for (int i=3;i<=n;i++) { // calculate these to avoid pointing off the end of the storage array mIter mi = m11 + (i-1) * n; mIter mii= m11 + (i-1) * n + i - 1; int im2 = i - 2; mIter mj = m11; mIter mji = mj + i - 1; mIter mij = mi; for (int j=1;j<=im2;j++) { s31 = 0.0; s32 = *mji; mIter mkj = mj + j - 1; mIter mik = mi + j - 1; mIter mjkp = mj + j; mIter mkpi = mj + n + i - 1; for (int k=j;k<=im2;k++) { s31 += (*mkj) * (*(mik++)); s32 += (*(mjkp++)) * (*mkpi); mkj += n; mkpi += n; } // for k *mij = -(*mii) * (((*(mij-n)))*( (*(mii-1)))+(s31)); *mji = -s32; mj += n; mji += n; mij++; } // for j *(mii-1) = -(*mii) * (*mimim) * (*(mii-1)); *(mimim+1) = -(*(mimim+1)); mimim += (n+1); } // for i } // n>2 mIter mi = m11; mIter mii = m11; for (int i=1;i> 12; int j = ij%4096; for (k=1; k<=n;k++) { // avoid setting the iterator beyond the end of the storage vector mIter mki = m11 + (k-1)*n + i - 1; mIter mkj = m11 + (k-1)*n + j - 1; // 2/24/05 David Sachs fix of improper swap bug that was present // for many years: double ti = *mki; // 2/24/05 *mki = *mkj; *mkj = ti; // 2/24/05 } } // for mm return 0; } int HepMatrix::dfact_matrix(double &det, int *ir) { if (ncol!=nrow) error("dfact_matrix: Matrix is not NxN"); int ifail, jfail; register int n = ncol; double tf; double g1 = 1.0e-19, g2 = 1.0e19; double p, q, t; double s11, s12; double epsilon = 8*DBL_EPSILON; // could be set to zero (like it was before) // but then the algorithm often doesn't detect // that a matrix is singular int normal = 0, imposs = -1; int jrange = 0, jover = 1, junder = -1; ifail = normal; jfail = jrange; int nxch = 0; det = 1.0; mIter mj = m.begin(); mIter mjj = mj; for (int j=1;j<=n;j++) { int k = j; p = (fabs(*mjj)); if (j!=n) { // replace mij with calculation of position for (int i=j+1;i p) { k = i; p = q; } } // for i if (k==j) { if (p <= epsilon) { det = 0; ifail = imposs; jfail = jrange; return ifail; } det = -det; // in this case the sign of the determinant // must not change. So I change it twice. } // k==j mIter mjl = mj; mIter mkl = m.begin() + (k-1)*n; for (int l=1;l<=n;l++) { tf = *mjl; *(mjl++) = *mkl; *(mkl++) = tf; } nxch = nxch + 1; // this makes the determinant change its sign ir[nxch] = (((j)<<12)+(k)); } else { // j!=n if (p <= epsilon) { det = 0.0; ifail = imposs; jfail = jrange; return ifail; } } // j!=n det *= *mjj; *mjj = 1.0 / *mjj; t = (fabs(det)); if (t < g1) { det = 0.0; if (jfail == jrange) jfail = junder; } else if (t > g2) { det = 1.0; if (jfail==jrange) jfail = jover; } // calculate mk and mkjp so we don't point off the end of the vector if (j!=n) { mIter mjk = mj + j; for (k=j+1;k<=n;k++) { mIter mk = mj + n*(k-j); mIter mkjp = mk + j; s11 = - (*mjk); s12 = - (*mkjp); if (j!=1) { mIter mik = m.begin() + k - 1; mIter mijp = m.begin() + j; mIter mki = mk; mIter mji = mj; for (int i=1;i max_array) { delete [] ir; max_array = nrow; ir = new int [max_array+1]; } double t1, t2, t3; double det, temp, s; int ifail; switch(nrow) { case 3: double c11,c12,c13,c21,c22,c23,c31,c32,c33; ifail = 0; c11 = (*(m.begin()+4)) * (*(m.begin()+8)) - (*(m.begin()+5)) * (*(m.begin()+7)); c12 = (*(m.begin()+5)) * (*(m.begin()+6)) - (*(m.begin()+3)) * (*(m.begin()+8)); c13 = (*(m.begin()+3)) * (*(m.begin()+7)) - (*(m.begin()+4)) * (*(m.begin()+6)); c21 = (*(m.begin()+7)) * (*(m.begin()+2)) - (*(m.begin()+8)) * (*(m.begin()+1)); c22 = (*(m.begin()+8)) * (*m.begin()) - (*(m.begin()+6)) * (*(m.begin()+2)); c23 = (*(m.begin()+6)) * (*(m.begin()+1)) - (*(m.begin()+7)) * (*m.begin()); c31 = (*(m.begin()+1)) * (*(m.begin()+5)) - (*(m.begin()+2)) * (*(m.begin()+4)); c32 = (*(m.begin()+2)) * (*(m.begin()+3)) - (*m.begin()) * (*(m.begin()+5)); c33 = (*m.begin()) * (*(m.begin()+4)) - (*(m.begin()+1)) * (*(m.begin()+3)); t1 = fabs(*m.begin()); t2 = fabs(*(m.begin()+3)); t3 = fabs(*(m.begin()+6)); if (t1 >= t2) { if (t3 >= t1) { temp = *(m.begin()+6); det = c23*c12-c22*c13; } else { temp = *(m.begin()); det = c22*c33-c23*c32; } } else if (t3 >= t2) { temp = *(m.begin()+6); det = c23*c12-c22*c13; } else { temp = *(m.begin()+3); det = c13*c32-c12*c33; } if (det==0) { ierr = 1; return; } { double s = temp/det; mIter mm = m.begin(); *(mm++) = s*c11; *(mm++) = s*c21; *(mm++) = s*c31; *(mm++) = s*c12; *(mm++) = s*c22; *(mm++) = s*c32; *(mm++) = s*c13; *(mm++) = s*c23; *(mm) = s*c33; } break; case 2: ifail = 0; det = (*m.begin())*(*(m.begin()+3)) - (*(m.begin()+1))*(*(m.begin()+2)); if (det==0) { ierr = 1; return; } s = 1.0/det; temp = s*(*(m.begin()+3)); *(m.begin()+1) *= -s; *(m.begin()+2) *= -s; *(m.begin()+3) = s*(*m.begin()); *(m.begin()) = temp; break; case 1: ifail = 0; if ((*(m.begin()))==0) { ierr = 1; return; } *(m.begin()) = 1.0/(*(m.begin())); break; case 4: invertHaywood4(ierr); return; case 5: invertHaywood5(ierr); return; case 6: invertHaywood6(ierr); return; default: ifail = dfact_matrix(det, ir); if(ifail) { ierr = 1; return; } dfinv_matrix(ir); break; } ierr = 0; return; } double HepMatrix::determinant() const { static int max_array = 20; static int *ir = new int [max_array+1]; if(ncol != nrow) error("HepMatrix::determinant: Matrix is not NxN"); if (ncol > max_array) { delete [] ir; max_array = nrow; ir = new int [max_array+1]; } double det; HepMatrix mt(*this); int i = mt.dfact_matrix(det, ir); if(i==0) return det; return 0; } double HepMatrix::trace() const { double t = 0.0; for (mcIter d = m.begin(); d < m.end(); d += (ncol+1) ) t += *d; return t; } } // namespace CLHEP