// -*- 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 "CLHEP/Matrix/defs.h" #include "CLHEP/Random/Random.h" #include "CLHEP/Matrix/SymMatrix.h" #include "CLHEP/Matrix/Matrix.h" #include "CLHEP/Matrix/DiagMatrix.h" #include "CLHEP/Matrix/Vector.h" #ifdef HEP_DEBUG_INLINE #include "CLHEP/Matrix/SymMatrix.icc" #endif namespace CLHEP { // Simple operation for all elements #define SIMPLE_UOP(OPER) \ register HepMatrix::mIter a=m.begin(); \ register HepMatrix::mIter e=m.begin()+num_size(); \ for(;a num_row()) error("HepSymMatrix::sub: Index out of range"); HepMatrix::mIter a = mret.m.begin(); HepMatrix::mcIter b1 = m.begin() + (min_row+2)*(min_row-1)/2; int rowsize=mret.num_row(); for(int irow=1; irow<=rowsize; irow++) { HepMatrix::mcIter b = b1; for(int icol=0; icol num_row()) error("HepSymMatrix::sub: Index out of range"); HepMatrix::mIter a = mret.m.begin(); HepMatrix::mIter b1 = m.begin() + (min_row+2)*(min_row-1)/2; int rowsize=mret.num_row(); for(int irow=1; irow<=rowsize; irow++) { HepMatrix::mIter b = b1; for(int icol=0; icol num_row() ) error("HepSymMatrix::sub: Index out of range"); HepMatrix::mcIter a = m1.m.begin(); HepMatrix::mIter b1 = m.begin() + (row+2)*(row-1)/2; int rowsize=m1.num_row(); for(int irow=1; irow<=rowsize; ++irow) { HepMatrix::mIter b = b1; for(int icol=0; icolm2.num_col() ){ mit2+=m2.num_col(); } } if(step= k for(int j=0; j!=nrow; ++j) { for(int k=0; k<=j; ++k) { m[j*ncol+k] += *sjk; // make sure this is not a diagonal element if(k!=j) m[k*nrow+j] += *sjk; ++sjk; } } return (*this); } HepSymMatrix & HepSymMatrix::operator+=(const HepSymMatrix &m2) { CHK_DIM_2(num_row(),m2.num_row(),num_col(),m2.num_col(),+=); SIMPLE_BOP(+=) return (*this); } HepMatrix & HepMatrix::operator-=(const HepSymMatrix &m2) { CHK_DIM_2(num_row(),m2.num_row(),num_col(),m2.num_col(),-=); HepMatrix::mcIter sjk = m2.m.begin(); // j >= k for(int j=0; j!=nrow; ++j) { for(int k=0; k<=j; ++k) { m[j*ncol+k] -= *sjk; // make sure this is not a diagonal element if(k!=j) m[k*nrow+j] -= *sjk; ++sjk; } } return (*this); } HepSymMatrix & HepSymMatrix::operator-=(const HepSymMatrix &m2) { CHK_DIM_2(num_row(),m2.num_row(),num_col(),m2.num_col(),-=); SIMPLE_BOP(-=) return (*this); } HepSymMatrix & HepSymMatrix::operator/=(double t) { SIMPLE_UOP(/=) return (*this); } HepSymMatrix & HepSymMatrix::operator*=(double t) { SIMPLE_UOP(*=) return (*this); } HepMatrix & HepMatrix::operator=(const HepSymMatrix &m1) { // define size, rows, and columns of *this nrow = ncol = m1.nrow; if(nrow*ncol != size_) { size_ = nrow*ncol; m.resize(size_); } // begin copy 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; } } return (*this); } HepSymMatrix & HepSymMatrix::operator=(const HepSymMatrix &m1) { if(m1.nrow != nrow) { nrow = m1.nrow; size_ = m1.size_; m.resize(size_); } m = m1.m; return (*this); } HepSymMatrix & HepSymMatrix::operator=(const HepDiagMatrix &m1) { if(m1.nrow != nrow) { nrow = m1.nrow; size_ = nrow * (nrow+1) / 2; m.resize(size_); } m.assign(size_,0); HepMatrix::mIter mrr = m.begin(); HepMatrix::mcIter mr = m1.m.begin(); for(int r=1; r<=nrow; r++) { *mrr = *(mr++); if(r= t2) { if (t3 >= t1) { temp = *(m.begin()+3); det = c23*c12-c22*c13; } else { temp = *m.begin(); det = c22*c33-c23*c23; } } else if (t3 >= t2) { temp = *(m.begin()+3); det = c23*c12-c22*c13; } else { temp = *(m.begin()+1); det = c13*c23-c12*c33; } if (det==0) { ifail = 1; return; } { double s = temp/det; HepMatrix::mIter mm = m.begin(); *(mm++) = s*c11; *(mm++) = s*c12; *(mm++) = s*c22; *(mm++) = s*c13; *(mm++) = s*c23; *(mm) = s*c33; } } break; case 2: { double det, temp, s; det = (*m.begin())*(*(m.begin()+2)) - (*(m.begin()+1))*(*(m.begin()+1)); if (det==0) { ifail = 1; return; } s = 1.0/det; *(m.begin()+1) *= -s; temp = s*(*(m.begin()+2)); *(m.begin()+2) = s*(*m.begin()); *m.begin() = temp; break; } case 1: { if ((*m.begin())==0) { ifail = 1; return; } *m.begin() = 1.0/(*m.begin()); break; } case 5: { invert5(ifail); return; } case 6: { invert6(ifail); return; } case 4: { invert4(ifail); return; } default: { invertBunchKaufman(ifail); return; } } return; // inversion successful } double HepSymMatrix::determinant() const { static const int max_array = 20; // ir must point to an array which is ***1 longer than*** nrow static std::vector ir_vec (max_array+1); if (ir_vec.size() <= static_cast(nrow)) ir_vec.resize(nrow+1); int * ir = &ir_vec[0]; double det; HepMatrix mt(*this); int i = mt.dfact_matrix(det, ir); if(i==0) return det; return 0.0; } double HepSymMatrix::trace() const { double t = 0.0; for (int i=0; i xvec (max_array); static std::vector pivv (max_array); typedef std::vector::iterator pivIter; #else static std::vector > xvec (max_array); static std::vector > pivv (max_array); typedef std::vector >::iterator pivIter; #endif if (xvec.size() < static_cast(nrow)) xvec.resize(nrow); if (pivv.size() < static_cast(nrow)) pivv.resize(nrow); // Note - resize shuld do nothing if the size is already larger than nrow, // but on VC++ there are indications that it does so we check. // Note - the data elements in a vector are guaranteed to be contiguous, // so x[i] and piv[i] are optimally fast. mIter x = xvec.begin(); // x[i] is used as helper storage, needs to have at least size nrow. pivIter piv = pivv.begin(); // piv[i] is used to store details of exchanges double temp1, temp2; HepMatrix::mIter ip, mjj, iq; double lambda, sigma; const double alpha = .6404; // = (1+sqrt(17))/8 const double epsilon = 32*DBL_EPSILON; // whenever a sum of two doubles is below or equal to epsilon // it is set to zero. // this constant could be set to zero but then the algorithm // doesn't neccessarily detect that a matrix is singular for (i = 0; i < nrow; ++i) piv[i] = i+1; ifail = 0; // compute the factorization P*A*P^T = L * D * L^T // L is unit lower triangular, D is direct sum of 1x1 and 2x2 matrices // L and D^-1 are stored in A = *this, P is stored in piv[] for (j=1; j < nrow; j+=s) // main loop over columns { mjj = m.begin() + j*(j-1)/2 + j-1; lambda = 0; // compute lambda = max of A(j+1:n,j) pivrow = j+1; //ip = m.begin() + (j+1)*j/2 + j-1; for (i=j+1; i <= nrow ; ++i) { // calculate ip to avoid going off end of storage array ip = m.begin() + (i-1)*i/2 + j-1; if (fabs(*ip) > lambda) { lambda = fabs(*ip); pivrow = i; } } // for i if (lambda == 0 ) { if (*mjj == 0) { ifail = 1; return; } s=1; *mjj = 1./ *mjj; } else { // lambda == 0 if (fabs(*mjj) >= lambda*alpha) { s=1; pivrow=j; } else { // fabs(*mjj) >= lambda*alpha sigma = 0; // compute sigma = max A(pivrow, j:pivrow-1) ip = m.begin() + pivrow*(pivrow-1)/2+j-1; for (k=j; k < pivrow; k++) { if (fabs(*ip) > sigma) sigma = fabs(*ip); ip++; } // for k if (sigma * fabs(*mjj) >= alpha * lambda * lambda) { s=1; pivrow = j; } else if (fabs(*(m.begin()+pivrow*(pivrow-1)/2+pivrow-1)) >= alpha * sigma) { s=1; } else { s=2; } // if sigma... } // fabs(*mjj) >= lambda*alpha if (pivrow == j) { // no permutation neccessary piv[j-1] = pivrow; if (*mjj == 0) { ifail=1; return; } temp2 = *mjj = 1./ *mjj; // invert D(j,j) // update A(j+1:n, j+1,n) for (i=j+1; i <= nrow; i++) { temp1 = *(m.begin() + i*(i-1)/2 + j-1) * temp2; ip = m.begin()+i*(i-1)/2+j; for (k=j+1; k<=i; k++) { *ip -= temp1 * *(m.begin() + k*(k-1)/2 + j-1); if (fabs(*ip) <= epsilon) *ip=0; ip++; } } // for i // update L //ip = m.begin() + (j+1)*j/2 + j-1; for (i=j+1; i <= nrow; ++i) { // calculate ip to avoid going off end of storage array ip = m.begin() + (i-1)*i/2 + j-1; *ip *= temp2; } } else if (s==1) { // 1x1 pivot piv[j-1] = pivrow; // interchange rows and columns j and pivrow in // submatrix (j:n,j:n) ip = m.begin() + pivrow*(pivrow-1)/2 + j; for (i=j+1; i < pivrow; i++, ip++) { temp1 = *(m.begin() + i*(i-1)/2 + j-1); *(m.begin() + i*(i-1)/2 + j-1)= *ip; *ip = temp1; } // for i temp1 = *mjj; *mjj = *(m.begin()+pivrow*(pivrow-1)/2+pivrow-1); *(m.begin()+pivrow*(pivrow-1)/2+pivrow-1) = temp1; ip = m.begin() + (pivrow+1)*pivrow/2 + j-1; iq = ip + pivrow-j; for (i = pivrow+1; i <= nrow; ip += i, iq += i++) { temp1 = *iq; *iq = *ip; *ip = temp1; } // for i if (*mjj == 0) { ifail = 1; return; } // *mjj == 0 temp2 = *mjj = 1./ *mjj; // invert D(j,j) // update A(j+1:n, j+1:n) for (i = j+1; i <= nrow; i++) { temp1 = *(m.begin() + i*(i-1)/2 + j-1) * temp2; ip = m.begin()+i*(i-1)/2+j; for (k=j+1; k<=i; k++) { *ip -= temp1 * *(m.begin() + k*(k-1)/2 + j-1); if (fabs(*ip) <= epsilon) *ip=0; ip++; } // for k } // for i // update L //ip = m.begin() + (j+1)*j/2 + j-1; for (i=j+1; i <= nrow; ++i) { // calculate ip to avoid going off end of storage array ip = m.begin() + (i-1)*i/2 + j-1; *ip *= temp2; } } else { // s=2, ie use a 2x2 pivot piv[j-1] = -pivrow; piv[j] = 0; // that means this is the second row of a 2x2 pivot if (j+1 != pivrow) { // interchange rows and columns j+1 and pivrow in // submatrix (j:n,j:n) ip = m.begin() + pivrow*(pivrow-1)/2 + j+1; for (i=j+2; i < pivrow; i++, ip++) { temp1 = *(m.begin() + i*(i-1)/2 + j); *(m.begin() + i*(i-1)/2 + j) = *ip; *ip = temp1; } // for i temp1 = *(mjj + j + 1); *(mjj + j + 1) = *(m.begin() + pivrow*(pivrow-1)/2 + pivrow-1); *(m.begin() + pivrow*(pivrow-1)/2 + pivrow-1) = temp1; temp1 = *(mjj + j); *(mjj + j) = *(m.begin() + pivrow*(pivrow-1)/2 + j-1); *(m.begin() + pivrow*(pivrow-1)/2 + j-1) = temp1; ip = m.begin() + (pivrow+1)*pivrow/2 + j; iq = ip + pivrow-(j+1); for (i = pivrow+1; i <= nrow; ip += i, iq += i++) { temp1 = *iq; *iq = *ip; *ip = temp1; } // for i } // j+1 != pivrow // invert D(j:j+1,j:j+1) temp2 = *mjj * *(mjj + j + 1) - *(mjj + j) * *(mjj + j); if (temp2 == 0) { std::cerr << "SymMatrix::bunch_invert: error in pivot choice" << std::endl; } temp2 = 1. / temp2; // this quotient is guaranteed to exist by the choice // of the pivot temp1 = *mjj; *mjj = *(mjj + j + 1) * temp2; *(mjj + j + 1) = temp1 * temp2; *(mjj + j) = - *(mjj + j) * temp2; if (j < nrow-1) { // otherwise do nothing // update A(j+2:n, j+2:n) for (i=j+2; i <= nrow ; i++) { ip = m.begin() + i*(i-1)/2 + j-1; temp1 = *ip * *mjj + *(ip + 1) * *(mjj + j); if (fabs(temp1 ) <= epsilon) temp1 = 0; temp2 = *ip * *(mjj + j) + *(ip + 1) * *(mjj + j + 1); if (fabs(temp2 ) <= epsilon) temp2 = 0; for (k = j+2; k <= i ; k++) { ip = m.begin() + i*(i-1)/2 + k-1; iq = m.begin() + k*(k-1)/2 + j-1; *ip -= temp1 * *iq + temp2 * *(iq+1); if (fabs(*ip) <= epsilon) *ip = 0; } // for k } // for i // update L for (i=j+2; i <= nrow ; i++) { ip = m.begin() + i*(i-1)/2 + j-1; temp1 = *ip * *mjj + *(ip+1) * *(mjj + j); if (fabs(temp1) <= epsilon) temp1 = 0; *(ip+1) = *ip * *(mjj + j) + *(ip+1) * *(mjj + j + 1); if (fabs(*(ip+1)) <= epsilon) *(ip+1) = 0; *ip = temp1; } // for k } // j < nrow-1 } } } // end of main loop over columns if (j == nrow) { // the the last pivot is 1x1 mjj = m.begin() + j*(j-1)/2 + j-1; if (*mjj == 0) { ifail = 1; return; } else { *mjj = 1. / *mjj; } } // end of last pivot code // computing the inverse from the factorization for (j = nrow ; j >= 1 ; j -= s) // loop over columns { mjj = m.begin() + j*(j-1)/2 + j-1; if (piv[j-1] > 0) { // 1x1 pivot, compute column j of inverse s = 1; if (j < nrow) { //ip = m.begin() + (j+1)*j/2 + j-1; //for (i=0; i < nrow-j; ip += 1+j+i++) x[i] = *ip; ip = m.begin() + (j+1)*j/2 - 1; for (i=0; i < nrow-j; ++i) { ip += i + j; x[i] = *ip; } for (i=j+1; i<=nrow ; i++) { temp2=0; ip = m.begin() + i*(i-1)/2 + j; for (k=0; k <= i-j-1; k++) temp2 += *ip++ * x[k]; // avoid setting ip outside the bounds of the storage array ip -= 1; // using the value of k from the previous loop for ( ; k < nrow-j; ++k) { ip += j+k; temp2 += *ip * x[k]; } *(m.begin()+ i*(i-1)/2 + j-1) = -temp2; } // for i temp2 = 0; //ip = m.begin() + (j+1)*j/2 + j-1; //for (k=0; k < nrow-j; ip += 1+j+k++) //temp2 += x[k] * *ip; ip = m.begin() + (j+1)*j/2 - 1; for (k=0; k < nrow-j; ++k) { ip += j+k; temp2 += x[k] * *ip; } *mjj -= temp2; } // j < nrow } else { //2x2 pivot, compute columns j and j-1 of the inverse if (piv[j-1] != 0) std::cerr << "error in piv" << piv[j-1] << std::endl; s=2; if (j < nrow) { //ip = m.begin() + (j+1)*j/2 + j-1; //for (i=0; i < nrow-j; ip += 1+j+i++) x[i] = *ip; ip = m.begin() + (j+1)*j/2 - 1; for (i=0; i < nrow-j; ++i) { ip += i + j; x[i] = *ip; } for (i=j+1; i<=nrow ; i++) { temp2 = 0; ip = m.begin() + i*(i-1)/2 + j; for (k=0; k <= i-j-1; k++) temp2 += *ip++ * x[k]; for (ip += i-1; k < nrow-j; ip += 1+j+k++) temp2 += *ip * x[k]; *(m.begin()+ i*(i-1)/2 + j-1) = -temp2; } // for i temp2 = 0; //ip = m.begin() + (j+1)*j/2 + j-1; //for (k=0; k < nrow-j; ip += 1+j+k++) temp2 += x[k] * *ip; ip = m.begin() + (j+1)*j/2 - 1; for (k=0; k < nrow-j; ++k) { ip += k + j; temp2 += x[k] * *ip; } *mjj -= temp2; temp2 = 0; //ip = m.begin() + (j+1)*j/2 + j-2; //for (i=j+1; i <= nrow; ip += i++) temp2 += *ip * *(ip+1); ip = m.begin() + (j+1)*j/2 - 2; for (i=j+1; i <= nrow; ++i) { ip += i - 1; temp2 += *ip * *(ip+1); } *(mjj-1) -= temp2; //ip = m.begin() + (j+1)*j/2 + j-2; //for (i=0; i < nrow-j; ip += 1+j+i++) x[i] = *ip; ip = m.begin() + (j+1)*j/2 - 2; for (i=0; i < nrow-j; ++i) { ip += i + j; x[i] = *ip; } for (i=j+1; i <= nrow ; i++) { temp2 = 0; ip = m.begin() + i*(i-1)/2 + j; for (k=0; k <= i-j-1; k++) temp2 += *ip++ * x[k]; for (ip += i-1; k < nrow-j; ip += 1+j+k++) temp2 += *ip * x[k]; *(m.begin()+ i*(i-1)/2 + j-2)= -temp2; } // for i temp2 = 0; //ip = m.begin() + (j+1)*j/2 + j-2; //for (k=0; k < nrow-j; ip += 1+j+k++) // temp2 += x[k] * *ip; ip = m.begin() + (j+1)*j/2 - 2; for (k=0; k < nrow-j; ++k) { ip += k + j; temp2 += x[k] * *ip; } *(mjj-j) -= temp2; } // j < nrow } // else piv[j-1] > 0 // interchange rows and columns j and piv[j-1] // or rows and columns j and -piv[j-2] pivrow = (piv[j-1]==0)? -piv[j-2] : piv[j-1]; ip = m.begin() + pivrow*(pivrow-1)/2 + j; for (i=j+1;i < pivrow; i++, ip++) { temp1 = *(m.begin() + i*(i-1)/2 + j-1); *(m.begin() + i*(i-1)/2 + j-1) = *ip; *ip = temp1; } // for i temp1 = *mjj; *mjj = *(m.begin() + pivrow*(pivrow-1)/2 + pivrow-1); *(m.begin() + pivrow*(pivrow-1)/2 + pivrow-1) = temp1; if (s==2) { temp1 = *(mjj-1); *(mjj-1) = *( m.begin() + pivrow*(pivrow-1)/2 + j-2); *( m.begin() + pivrow*(pivrow-1)/2 + j-2) = temp1; } // s==2 // problem right here if( pivrow < nrow ) { ip = m.begin() + (pivrow+1)*pivrow/2 + j-1; // &A(i,j) // adding parenthesis for VC++ iq = ip + (pivrow-j); for (i = pivrow+1; i <= nrow; i++) { temp1 = *iq; *iq = *ip; *ip = temp1; if( i < nrow ) { ip += i; iq += i; } } // for i } // pivrow < nrow } // end of loop over columns (in computing inverse from factorization) return; // inversion successful } } // namespace CLHEP