diff --git a/smatrix/inc/Math/Dinv.h b/smatrix/inc/Math/Dinv.h index 6ea9243a27ef444c179f705e796eecc0d304900d..baf42e99c11217f6c3fa82218e77b53d3cbf0ef9 100644 --- a/smatrix/inc/Math/Dinv.h +++ b/smatrix/inc/Math/Dinv.h @@ -1,4 +1,4 @@ -// @(#)root/smatrix:$Name: $:$Id: Dinv.h,v 1.3 2005/12/07 16:44:05 moneta Exp $ +// @(#)root/smatrix:$Name: $:$Id: Dinv.h,v 1.4 2006/02/08 14:45:35 moneta Exp $ // Authors: T. Glebe, L. Moneta 2005 #ifndef ROOT_Math_Dinv @@ -67,7 +67,7 @@ public: } #endif - +#ifdef OLD_IMPL /* Initialized data */ static unsigned int work[n]; @@ -83,6 +83,23 @@ public: return false; } return Dfinv<MatrixRep,n,idim>(rhs,work); +#else + + /* Initialized data */ + static unsigned int work[n+1]; + for(unsigned int i=0; i<n+1; ++i) work[i] = 0; + + static typename MatrixRep::value_type det = 0; + + if (DfactMatrix(rhs,det,work) != 0) { + std::cerr << "Dfact_matrix failed!!" << std::endl; + return false; + } + + int ifail = DfinvMatrix(rhs,work); + if (ifail == 0) return true; + return false; +#endif } // Dinv @@ -91,6 +108,7 @@ public: static bool Dinv(MatRepSym<T,idim> & rhs) { // not very efficient but need to re-do Dsinv for new storage of // symmetric matrices +#ifdef OLD_IMPL MatRepStd<T,idim> tmp; for (unsigned int i = 0; i< idim*idim; ++i) tmp[i] = rhs[i]; @@ -100,9 +118,30 @@ public: rhs[i] = tmp[i]; return true; +#else + int ifail = 0; + InvertBunchKaufman(rhs,ifail); + if (ifail == 0) return true; + return false; +#endif } + /** + Bunch-Kaufman method for inversion of symmetric matrices + */ + template <class T> + static int DfactMatrix(MatRepStd<T,idim,n> & rhs, T & det, unsigned int * work); + template <class T> + static int DfinvMatrix(MatRepStd<T,idim,n> & rhs, unsigned int * work); + + /** + Bunch-Kaufman method for inversion of symmetric matrices + */ + template <class T> + static void InvertBunchKaufman(MatRepSym<T,idim> & rhs, int &ifail); + + }; // class Inverter @@ -279,5 +318,6 @@ public: #include "CramerInversion.icc" #include "CramerInversionSym.icc" +#include "MatrixInversion.icc" #endif /* ROOT_Math_Dinv */ diff --git a/smatrix/inc/Math/MatrixFunctions.h b/smatrix/inc/Math/MatrixFunctions.h index a190e2d4123f179190b1ce3404a476d8a2831a51..4001fe5e0cb0e89fdaa0f37909277cef6a1e91a7 100644 --- a/smatrix/inc/Math/MatrixFunctions.h +++ b/smatrix/inc/Math/MatrixFunctions.h @@ -1,4 +1,4 @@ -// @(#)root/smatrix:$Name: $:$Id: MatrixFunctions.h,v 1.9 2006/03/20 17:11:44 moneta Exp $ +// @(#)root/smatrix:$Name: $:$Id: MatrixFunctions.h,v 1.10 2006/04/25 13:54:01 moneta Exp $ // Authors: T. Glebe, L. Moneta 2005 #ifndef ROOT_Math_MatrixFunctions @@ -57,6 +57,10 @@ SVector<T,D1> operator*(const SMatrix<T,D1,D2,R>& rhs, const SVector<T,D2>& lhs) #endif +// matrix-vector product: +// use apply(i) funciton for matrices. Tested (11/05/06) with using (i,j) but +// performances are slightly worse (not clear why) + //============================================================================== // meta_row_dot //============================================================================== @@ -736,6 +740,88 @@ inline SMatrix<T,D2,D2,MatRepSym<T,D2> > SimilarityT(const Expr<A,T,D1,D2,R>& lh +//============================================================================== +// TensorMulOp +// tensor (or outer) product between two vectors giving a matrix +//============================================================================== +template <class Vector1, class Vector2> +class TensorMulOp { +public: + /// + TensorMulOp( const Vector1 & lhs, const Vector2 & rhs) : + lhs_(lhs), + rhs_(rhs) {} + + /// + ~TensorMulOp() {} + + /// Vector2::kSize is the number of columns in the resulting matrix + inline typename Vector1::value_type apply(unsigned int i) const { + return lhs_.apply( i/ Vector2::kSize) * rhs_.apply( i % Vector2::kSize ); + } + inline typename Vector1::value_type operator() (unsigned int i, unsigned j) const { + return lhs_.apply(i) * rhs_.apply(j); + } + + inline bool IsInUse (const typename Vector1::value_type * ) const { + return false; + } + + +protected: + + const Vector1 & lhs_; + const Vector2 & rhs_; + +}; + + // Tensor Prod (use default MatRepStd for the returned expression + // cannot make a symmetric matrix +//============================================================================== +// TensorProd (SVector x SVector) +//============================================================================== +template < class T, unsigned int D1, unsigned int D2> +inline Expr<TensorMulOp<SVector<T,D1>, SVector<T,D2> >, T, D1, D2 > + TensorProd(const SVector<T,D1>& lhs, const SVector<T,D2>& rhs) { + typedef TensorMulOp<SVector<T,D1>, SVector<T,D2> > TVMulOp; + return Expr<TVMulOp,T,D1,D2>(TVMulOp(lhs,rhs)); +} + +//============================================================================== +// TensorProd (VecExpr x SVector) +//============================================================================== +template <class A, class T, unsigned int D1, unsigned int D2> +inline Expr<TensorMulOp<VecExpr<A,T,D1>, SVector<T,D2> >, T, D1, D2 > + TensorProd(const VecExpr<A,T,D1>& lhs, const SVector<T,D2>& rhs) { + typedef TensorMulOp<VecExpr<A,T,D1>, SVector<T,D2> > TVMulOp; + return Expr<TVMulOp,T,D1,D2>(TVMulOp(lhs,rhs)); +} + +//============================================================================== +// TensorProd (SVector x VecExpr) +//============================================================================== +template <class A, class T, unsigned int D1, unsigned int D2> +inline Expr<TensorMulOp<SVector<T,D1>, VecExpr<A,T,D2> >, T, D1, D2 > + TensorProd(const SVector<T,D1>& lhs, const VecExpr<A,T,D2>& rhs) { + typedef TensorMulOp<SVector<T,D1>, VecExpr<A,T,D2> > TVMulOp; + return Expr<TVMulOp,T,D1,D2>(TVMulOp(lhs,rhs)); +} + + +//============================================================================== +// TensorProd (VecExpr x VecExpr) +//============================================================================== +template <class A, class B, class T, unsigned int D1, unsigned int D2> +inline Expr<TensorMulOp<VecExpr<A,T,D1>, VecExpr<B,T,D2> >, T, D1, D2 > + TensorProd(const VecExpr<A,T,D1>& lhs, const VecExpr<B,T,D2>& rhs) { + typedef TensorMulOp<VecExpr<A,T,D1>, VecExpr<B,T,D2> > TVMulOp; + return Expr<TVMulOp,T,D1,D2>(TVMulOp(lhs,rhs)); +} + + + + + } // namespace Math } // namespace ROOT diff --git a/smatrix/inc/Math/MatrixInversion.icc b/smatrix/inc/Math/MatrixInversion.icc new file mode 100644 index 0000000000000000000000000000000000000000..8e62d1214a937d5d7a3ffe17c910027990dcef7b --- /dev/null +++ b/smatrix/inc/Math/MatrixInversion.icc @@ -0,0 +1,659 @@ +// @(#)root/smatrix:$Name: $:$Id: MatrixInversion.icc,v 1.1 2006/02/08 14:45:35 moneta Exp $ +// Authors: CLHEP authors, L. Moneta 2006 + +#include "Math/SVector.h" + + +// inversion algorithms for matrices +// taken from CLHEP (L. Moneta May 2006) + +namespace ROOT { + + namespace Math { + + + /** Bunch-Kaufman diagonal pivoting method + It is decribed in J.R. Bunch, L. Kaufman (1977). + "Some Stable Methods for Calculating Inertia and Solving Symmetric + Linear Systems", Math. Comp. 31, p. 162-179. or in Gene H. Golub, + /Charles F. van Loan, "Matrix Computations" (the second edition + has a bug.) and implemented in "lapack" + Mario Stanke, 09/97 + + */ + +template <unsigned int idim, unsigned int N> +template<class T> +void Inverter<idim,N>::InvertBunchKaufman(MatRepSym<T,idim> & rhs, int &ifail) { + + + + + int i, j, k, s; + int pivrow; + + const int nrow = N; + + // Establish the two working-space arrays needed: x and piv are + // used as pointers to arrays of doubles and ints respectively, each + // of length nrow. We do not want to reallocate each time through + // unless the size needs to grow. We do not want to leak memory, even + // by having a new without a delete that is only done once. + + + static SVector<double, N> xvec; + static SVector<int, N> pivv; + + typedef int* pivIter; + typedef T* mIter; + + + // 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; + mIter ip, mjj, iq; + double lambda, sigma; + const double alpha = .6404; // = (1+sqrt(17))/8 + const double epsilon = 32*std::numeric_limits<T>::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 = rhs.Array() + j*(j-1)/2 + j-1; + lambda = 0; // compute lambda = max of A(j+1:n,j) + pivrow = j+1; + ip = rhs.Array() + (j+1)*j/2 + j-1; + for (i=j+1; i <= nrow ; ip += i++) + if (std::fabs(*ip) > lambda) + { + lambda = std::fabs(*ip); + pivrow = i; + } + + if (lambda == 0 ) + { + if (*mjj == 0) + { + ifail = 1; + return; + } + s=1; + *mjj = 1./ *mjj; + } + else + { + if (std::fabs(*mjj) >= lambda*alpha) + { + s=1; + pivrow=j; + } + else + { + sigma = 0; // compute sigma = max A(pivrow, j:pivrow-1) + ip = rhs.Array() + pivrow*(pivrow-1)/2+j-1; + for (k=j; k < pivrow; k++) + { + if (std::fabs(*ip) > sigma) + sigma = std::fabs(*ip); + ip++; + } + if (sigma * std::fabs(*mjj) >= alpha * lambda * lambda) + { + s=1; + pivrow = j; + } + else if (std::fabs(*(rhs.Array()+pivrow*(pivrow-1)/2+pivrow-1)) + >= alpha * sigma) + s=1; + else + s=2; + } + 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 = *(rhs.Array() + i*(i-1)/2 + j-1) * temp2; + ip = rhs.Array()+i*(i-1)/2+j; + for (k=j+1; k<=i; k++) + { + *ip -= temp1 * *(rhs.Array() + k*(k-1)/2 + j-1); + if (std::fabs(*ip) <= epsilon) + *ip=0; + ip++; + } + } + // update L + ip = rhs.Array() + (j+1)*j/2 + j-1; + for (i=j+1; i <= nrow; ip += i++) + *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 = rhs.Array() + pivrow*(pivrow-1)/2 + j; + for (i=j+1; i < pivrow; i++, ip++) + { + temp1 = *(rhs.Array() + i*(i-1)/2 + j-1); + *(rhs.Array() + i*(i-1)/2 + j-1)= *ip; + *ip = temp1; + } + temp1 = *mjj; + *mjj = *(rhs.Array()+pivrow*(pivrow-1)/2+pivrow-1); + *(rhs.Array()+pivrow*(pivrow-1)/2+pivrow-1) = temp1; + ip = rhs.Array() + (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; + } + + 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 = *(rhs.Array() + i*(i-1)/2 + j-1) * temp2; + ip = rhs.Array()+i*(i-1)/2+j; + for (k=j+1; k<=i; k++) + { + *ip -= temp1 * *(rhs.Array() + k*(k-1)/2 + j-1); + if (std::fabs(*ip) <= epsilon) + *ip=0; + ip++; + } + } + // update L + ip = rhs.Array() + (j+1)*j/2 + j-1; + for (i=j+1; i<=nrow; ip += i++) + *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 = rhs.Array() + pivrow*(pivrow-1)/2 + j+1; + for (i=j+2; i < pivrow; i++, ip++) + { + temp1 = *(rhs.Array() + i*(i-1)/2 + j); + *(rhs.Array() + i*(i-1)/2 + j) = *ip; + *ip = temp1; + } + temp1 = *(mjj + j + 1); + *(mjj + j + 1) = + *(rhs.Array() + pivrow*(pivrow-1)/2 + pivrow-1); + *(rhs.Array() + pivrow*(pivrow-1)/2 + pivrow-1) = temp1; + temp1 = *(mjj + j); + *(mjj + j) = *(rhs.Array() + pivrow*(pivrow-1)/2 + j-1); + *(rhs.Array() + pivrow*(pivrow-1)/2 + j-1) = temp1; + ip = rhs.Array() + (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; + } + } + // 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 = rhs.Array() + i*(i-1)/2 + j-1; + temp1 = *ip * *mjj + *(ip + 1) * *(mjj + j); + if (std::fabs(temp1 ) <= epsilon) + temp1 = 0; + temp2 = *ip * *(mjj + j) + *(ip + 1) * *(mjj + j + 1); + if (std::fabs(temp2 ) <= epsilon) + temp2 = 0; + for (k = j+2; k <= i ; k++) + { + ip = rhs.Array() + i*(i-1)/2 + k-1; + iq = rhs.Array() + k*(k-1)/2 + j-1; + *ip -= temp1 * *iq + temp2 * *(iq+1); + if (std::fabs(*ip) <= epsilon) + *ip = 0; + } + } + // update L + for (i=j+2; i <= nrow ; i++) + { + ip = rhs.Array() + i*(i-1)/2 + j-1; + temp1 = *ip * *mjj + *(ip+1) * *(mjj + j); + if (std::fabs(temp1) <= epsilon) + temp1 = 0; + *(ip+1) = *ip * *(mjj + j) + + *(ip+1) * *(mjj + j + 1); + if (std::fabs(*(ip+1)) <= epsilon) + *(ip+1) = 0; + *ip = temp1; + } + } + } + } + } // end of main loop over columns + + if (j == nrow) // the the last pivot is 1x1 + { + mjj = rhs.Array() + 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 = rhs.Array() + j*(j-1)/2 + j-1; + if (piv[j-1] > 0) // 1x1 pivot, compute column j of inverse + { + s = 1; + if (j < nrow) + { + ip = rhs.Array() + (j+1)*j/2 + j-1; + for (i=0; i < nrow-j; ip += 1+j+i++) + x[i] = *ip; + for (i=j+1; i<=nrow ; i++) + { + temp2=0; + ip = rhs.Array() + 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]; + *(rhs.Array()+ i*(i-1)/2 + j-1) = -temp2; + } + temp2 = 0; + ip = rhs.Array() + (j+1)*j/2 + j-1; + for (k=0; k < nrow-j; ip += 1+j+k++) + temp2 += x[k] * *ip; + *mjj -= temp2; + } + } + 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 = rhs.Array() + (j+1)*j/2 + j-1; + for (i=0; i < nrow-j; ip += 1+j+i++) + x[i] = *ip; + for (i=j+1; i<=nrow ; i++) + { + temp2 = 0; + ip = rhs.Array() + 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]; + *(rhs.Array()+ i*(i-1)/2 + j-1) = -temp2; + } + temp2 = 0; + ip = rhs.Array() + (j+1)*j/2 + j-1; + for (k=0; k < nrow-j; ip += 1+j+k++) + temp2 += x[k] * *ip; + *mjj -= temp2; + temp2 = 0; + ip = rhs.Array() + (j+1)*j/2 + j-2; + for (i=j+1; i <= nrow; ip += i++) + temp2 += *ip * *(ip+1); + *(mjj-1) -= temp2; + ip = rhs.Array() + (j+1)*j/2 + j-2; + for (i=0; i < nrow-j; ip += 1+j+i++) + x[i] = *ip; + for (i=j+1; i <= nrow ; i++) + { + temp2 = 0; + ip = rhs.Array() + 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]; + *(rhs.Array()+ i*(i-1)/2 + j-2)= -temp2; + } + temp2 = 0; + ip = rhs.Array() + (j+1)*j/2 + j-2; + for (k=0; k < nrow-j; ip += 1+j+k++) + temp2 += x[k] * *ip; + *(mjj-j) -= temp2; + } + } + + // 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 = rhs.Array() + pivrow*(pivrow-1)/2 + j; + for (i=j+1;i < pivrow; i++, ip++) + { + temp1 = *(rhs.Array() + i*(i-1)/2 + j-1); + *(rhs.Array() + i*(i-1)/2 + j-1) = *ip; + *ip = temp1; + } + temp1 = *mjj; + *mjj = *(rhs.Array() + pivrow*(pivrow-1)/2 + pivrow-1); + *(rhs.Array() + pivrow*(pivrow-1)/2 + pivrow-1) = temp1; + if (s==2) + { + temp1 = *(mjj-1); + *(mjj-1) = *( rhs.Array() + pivrow*(pivrow-1)/2 + j-2); + *( rhs.Array() + pivrow*(pivrow-1)/2 + j-2) = temp1; + } + + ip = rhs.Array() + (pivrow+1)*pivrow/2 + j-1; // &A(i,j) + iq = ip + pivrow-j; + for (i = pivrow+1; i <= nrow; ip += i, iq += i++) + { + temp1 = *iq; + *iq = *ip; + *ip = temp1; + } + } // end of loop over columns (in computing inverse from factorization) + + return; // inversion successful + +} + + + + + /** + LU factorization : code originally from CERNLIB dfact routine and ported in C++ for CLHEP + */ + +template <unsigned int idim, unsigned int n> +template<class T> +int Inverter<idim,n>::DfactMatrix(MatRepStd<T,idim,n> & rhs, T &det, unsigned int *ir) { + + if (idim != n) return -1; + + int ifail, jfail; + + typedef T* mIter; + + + double tf; + double g1 = 1.0e-19, g2 = 1.0e19; + + double p, q, t; + double s11, s12; + + double epsilon = 8*std::numeric_limits<double>::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 = rhs.Array(); + mIter mjj = mj; + for (unsigned int j=1;j<=n;j++) { + unsigned int k = j; + p = (std::fabs(*mjj)); + if (j!=n) { + mIter mij = mj + n + j - 1; + for (unsigned int i=j+1;i<=n;i++) { + q = (std::fabs(*(mij))); + if (q > p) { + k = i; + p = q; + } + mij += n; + } + 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. + } + mIter mjl = mj; + mIter mkl = rhs.Array() + (k-1)*n; + for (unsigned 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 { + if (p <= epsilon) { + det = 0.0; + ifail = imposs; + jfail = jrange; + return ifail; + } + } + det *= *mjj; + *mjj = 1.0 / *mjj; + t = (std::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; + } + if (j!=n) { + mIter mk = mj + n; + mIter mkjp = mk + j; + mIter mjk = mj + j; + for (unsigned k=j+1;k<=n;k++) { + s11 = - (*mjk); + s12 = - (*mkjp); + if (j!=1) { + mIter mik = rhs.Array() + k - 1; + mIter mijp = rhs.Array() + j; + mIter mki = mk; + mIter mji = mj; + for (unsigned int i=1;i<j;i++) { + s11 += (*mik) * (*(mji++)); + s12 += (*mijp) * (*(mki++)); + mik += n; + mijp += n; + } + } + *(mjk++) = -s11 * (*mjj); + *(mkjp) = -(((*(mjj+1)))*((*(mkjp-1)))+(s12)); + mk += n; + mkjp += n; + } + } + mj += n; + mjj += (n+1); + } + if (nxch%2==1) det = -det; + if (jfail !=jrange) det = 0.0; + ir[n] = nxch; + return 0; +} + + + + /** + Inversion for General square matrices. Code from dfinv routine from CERNLIB + Assumed first the LU decomposition via DfactMatrix function + + taken from CLHEP : L. Moneta May 2006 + */ + +template <unsigned int idim, unsigned int n> +template<class T> +int Inverter<idim,n>::DfinvMatrix(MatRepStd<T,idim,n> & rhs,unsigned int * ir) { + + + typedef T* mIter; + + if (idim != n) return -1; + + + double s31, s32; + register double s33, s34; + + mIter m11 = rhs.Array(); + mIter m12 = m11 + 1; + mIter m21 = m11 + n; + mIter m22 = m12 + n; + *m21 = -(*m22) * (*m11) * (*m21); + *m12 = -(*m12); + if (n>2) { + mIter mi = rhs.Array() + 2 * n; + mIter mii= rhs.Array() + 2 * n + 2; + mIter mimim = rhs.Array() + n + 1; + for (unsigned int i=3;i<=n;i++) { + unsigned int im2 = i - 2; + mIter mj = rhs.Array(); + mIter mji = mj + i - 1; + mIter mij = mi; + for (unsigned 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 (unsigned int k=j;k<=im2;k++) { + s31 += (*mkj) * (*(mik++)); + s32 += (*(mjkp++)) * (*mkpi); + mkj += n; + mkpi += n; + } + *mij = -(*mii) * (((*(mij-n)))*( (*(mii-1)))+(s31)); + *mji = -s32; + mj += n; + mji += n; + mij++; + } + *(mii-1) = -(*mii) * (*mimim) * (*(mii-1)); + *(mimim+1) = -(*(mimim+1)); + mi += n; + mimim += (n+1); + mii += (n+1); + } + } + mIter mi = rhs.Array(); + mIter mii = rhs.Array(); + for (unsigned int i=1;i<n;i++) { + unsigned int ni = n - i; + mIter mij = mi; + //int j; + for (unsigned j=1; j<=i;j++) { + s33 = *mij; + register mIter mikj = mi + n + j - 1; + register mIter miik = mii + 1; + mIter min_end = mi + n; + for (;miik<min_end;) { + s33 += (*mikj) * (*(miik++)); + mikj += n; + } + *(mij++) = s33; + } + for (unsigned j=1;j<=ni;j++) { + s34 = 0.0; + mIter miik = mii + j; + mIter mikij = mii + j * n + j; + for (unsigned int k=j;k<=ni;k++) { + s34 += *mikij * (*(miik++)); + mikij += n; + } + *(mii+j) = s34; + } + mi += n; + mii += (n+1); + } + unsigned int nxch = ir[n]; + if (nxch==0) return 0; + for (unsigned int mm=1;mm<=nxch;mm++) { + unsigned int k = nxch - mm + 1; + int ij = ir[k]; + int i = ij >> 12; + int j = ij%4096; + mIter mki = rhs.Array() + i - 1; + mIter mkj = rhs.Array() + j - 1; + for (k=1; k<=n;k++) { + // 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 + mki += n; + mkj += n; + } + } + return 0; +} + + + } // end namespace Math +} // end namespace ROOT diff --git a/smatrix/inc/Math/SMatrix.h b/smatrix/inc/Math/SMatrix.h index f28e456da0fc8f5482c3597af1480fe9ba21b807..bfc5eaf8eb1ba5f62c3002dd3de68a0f96b25c14 100644 --- a/smatrix/inc/Math/SMatrix.h +++ b/smatrix/inc/Math/SMatrix.h @@ -1,4 +1,4 @@ -// @(#)root/smatrix:$Name: $:$Id: SMatrix.h,v 1.19 2006/04/20 13:13:21 moneta Exp $ +// @(#)root/smatrix:$Name: $:$Id: SMatrix.h,v 1.20 2006/04/25 13:54:01 moneta Exp $ // Authors: T. Glebe, L. Moneta 2005 #ifndef ROOT_Math_SMatrix @@ -337,6 +337,7 @@ public: #endif +#ifdef OLD_IMPL /** @name --- Expert functions --- */ /** @@ -362,19 +363,23 @@ public: this method will preserve the contents of the Matrix! */ bool Sdet2(T& det) const; +#endif /** - invert square Matrix via Dinv. - This method change the current matrix + invert square Matrix ( this method change the current matrix) + The method used for general square matrices is the LU factorization taken from Dinv routine + from the CERNLIB (written in C++ from CLHEP authors) + In case of symmetric matrices Bunch-Kaufman diagonal pivoting method is used + (The implementation is the one written by the CLHEP authors) */ bool Invert(); /** - invert square Matrix via Dinv. - This method returns a new matrix. In case the inversion fails - the current matrix is returned - Return ifail = 0 when successfull + invert a square Matrix and returns a new matrix. In case the inversion fails + the current matrix is returned. + Return ifail = 0 when successfull. + See ROOT::Math::SMatrix::Invert for the inversion algorithm */ SMatrix<T,D1,D2,R> Inverse(int & ifail ) const; diff --git a/smatrix/inc/Math/SMatrix.icc b/smatrix/inc/Math/SMatrix.icc index 512986519417b8eb647c3001b72b1aa889c83124..7efd8041916a35a3f3a861322388c5822fd06cb2 100644 --- a/smatrix/inc/Math/SMatrix.icc +++ b/smatrix/inc/Math/SMatrix.icc @@ -1,4 +1,4 @@ -// @(#)root/smatrix:$Name: $:$Id: SMatrix.icc,v 1.19 2006/03/30 16:18:05 moneta Exp $ +// @(#)root/smatrix:$Name: $:$Id: SMatrix.icc,v 1.20 2006/04/25 13:54:01 moneta Exp $ // Authors: T. Glebe, L. Moneta 2005 #ifndef ROOT_Math_SMatrix_icc @@ -431,6 +431,7 @@ bool SMatrix<T,D1,D2,R>::operator<(const Expr<A,T,D1,D2,R2>& rhs) const { return rc; } +#ifdef OLD_IMPL //============================================================================== // sinvert //============================================================================== @@ -451,7 +452,6 @@ inline SMatrix<T,D1,D2,R> SMatrix<T,D1,D2,R>::Sinverse(int & ifail) const { } - //============================================================================== // sdet //============================================================================== @@ -469,6 +469,7 @@ inline bool SMatrix<T,D1,D2,R>::Sdet2(T& det) const { return tmp.Sdet(det); } +#endif //============================================================================== // invert @@ -476,7 +477,7 @@ inline bool SMatrix<T,D1,D2,R>::Sdet2(T& det) const { template <class T, unsigned int D1, unsigned int D2, class R> inline bool SMatrix<T,D1,D2,R>::Invert() { STATIC_CHECK( D1 == D2,SMatrix_not_square); - return Inverter<D1>::Dinv((*this).fRep); + return Inverter<D1,D2>::Dinv((*this).fRep); } template <class T, unsigned int D1, unsigned int D2, class R> diff --git a/smatrix/inc/Math/SVector.h b/smatrix/inc/Math/SVector.h index 82174e70a0627c6418516656f9853635d85a8e6d..22239f94654a82d2e3f1176f2098f10287ae78f6 100644 --- a/smatrix/inc/Math/SVector.h +++ b/smatrix/inc/Math/SVector.h @@ -1,4 +1,4 @@ -// @(#)root/smatrix:$Name: $:$Id: SVector.h,v 1.7 2006/02/27 18:41:58 moneta Exp $ +// @(#)root/smatrix:$Name: $:$Id: SVector.h,v 1.8 2006/04/20 13:13:21 moneta Exp $ // Authors: T. Glebe, L. Moneta 2005 #ifndef ROOT_Math_SVector @@ -119,7 +119,12 @@ public: // if you use iterator this is not necessary /// fill from array, len must be equal to D! - SVector(const T* a, unsigned int len); + SVector( const T * a, unsigned int len); + + /// fill from iterators + //(iterator is T* to skip ambiguities) + SVector(const_iterator begin, const_iterator end); + #endif /// SVector(const T& rhs); diff --git a/smatrix/inc/Math/SVector.icc b/smatrix/inc/Math/SVector.icc index 427e01a50f5299738db25c9aa2c19196e3ca130c..10f36322733fce3e2fa019b731594cd75dec263a 100644 --- a/smatrix/inc/Math/SVector.icc +++ b/smatrix/inc/Math/SVector.icc @@ -1,4 +1,4 @@ -// @(#)root/smatrix:$Name: $:$Id: SVector.icc,v 1.6 2006/02/08 14:45:35 moneta Exp $ +// @(#)root/smatrix:$Name: $:$Id: SVector.icc,v 1.7 2006/02/27 18:41:58 moneta Exp $ // Authors: T. Glebe, L. Moneta 2005 #ifndef ROOT_Math_SVector_icc @@ -114,6 +114,13 @@ SVector<T,D>::SVector(const T* a, unsigned int len) { fArray[i] = a[i]; } +template <class T, unsigned int D> +SVector<T,D>::SVector(const_iterator begin, const_iterator end) { + assert( begin + D == end); + std::copy(begin, end, fArray); +} + + #endif template <class T, unsigned int D> diff --git a/smatrix/test/Makefile b/smatrix/test/Makefile index a16ed9d748d435fa78a412de40552999f1c737b2..2ecde26e1fd1f8864f1d299dd4043e5fff235c93 100644 --- a/smatrix/test/Makefile +++ b/smatrix/test/Makefile @@ -12,7 +12,7 @@ include ../../test/Makefile.arch ifeq ($(PLATFORM),macosx) #unroll loop better on gcc > 4 -CXXFLAGS+= -g -funroll-loops +CXXFLAGS+= -O3 -g -funroll-loops endif # if have clhep diff --git a/smatrix/test/stressKalman.cxx b/smatrix/test/stressKalman.cxx index d53a4a69de9767f5f47c4147c9bdfb22351afd09..db93ffbf7fea98d3ec92744304b0928426cd7b87 100644 --- a/smatrix/test/stressKalman.cxx +++ b/smatrix/test/stressKalman.cxx @@ -19,7 +19,7 @@ #include <map> - +//#undef HAVE_CLHEP #ifdef HAVE_CLHEP #include "CLHEP/Matrix/SymMatrix.h" @@ -58,7 +58,7 @@ public: test_smatrix_kalman(); test_tmatrix_kalman(); #ifdef HAVE_CLHEP - test_clhep_matrix(); + test_clhep_kalman(); #endif return; @@ -188,8 +188,8 @@ void printTime(TStopwatch & time, std::string s) { } // reference times for sizes <=6 and > 6 on Linux slc3 P4 3Ghz ("SMatrix","SMatrix_sym","TMatrix") -double refTime1[3] = { 40.49, 53.75, 83.21 }; -double refTime2[3] = { 393.81, 462.16, 785.50 }; +double refTime1[4] = { 40.49, 53.75, 83.21,1000 }; +double refTime2[4] = { 393.81, 462.16, 785.50,10000 }; #define NMAX1 9 // matrix storese results from 2 to 10 #define NMAX2 7 // results from 2 to 8 @@ -807,8 +807,8 @@ int TestRunner<NDIM1,NDIM2>::test_clhep_kalman() { fillRandomMat(r,K0,second,first,1); fillRandomSym(r,Cp,second,1); fillRandomSym(r,V,first,1); - fillRandomVec(r,m,first,1); - fillRandomVec(r,xp,second,1); + fillRandomVec(r,m,first); + fillRandomVec(r,xp,second); MnSymMatrix I(second,1);//Identity matrix @@ -843,12 +843,11 @@ int TestRunner<NDIM1,NDIM2>::test_clhep_kalman() { x2= RinvSym.similarity(vtmp1); if(ifail!=0) { std::cout << "Error inverting Rinv" << std::endl; break; } } - // std::cout << k << " chi2 " << x2 << std::endl; x2sum += x2; c2 = 0; - for (int i=1; i<=NDIM2; ++i) - for (int j=1; j<=NDIM2; ++j) + for (unsigned int i=1; i<=NDIM2; ++i) + for (unsigned int j=1; j<=NDIM2; ++j) c2 += C(i,j); c2sum += c2; } diff --git a/smatrix/test/testKalman.cxx b/smatrix/test/testKalman.cxx index bbc408697915257fdffa219f444375078016d076..c9ee5ce65f92523d3237ceb617139034a050a86a 100644 --- a/smatrix/test/testKalman.cxx +++ b/smatrix/test/testKalman.cxx @@ -489,8 +489,8 @@ int test_clhep_kalman() { fillRandomMat(r,K0,second,first,1); fillRandomSym(r,Cp,second,1); fillRandomSym(r,V,first,1); - fillRandomVec(r,m,first,1); - fillRandomVec(r,xp,second,1); + fillRandomVec(r,m,first); + fillRandomVec(r,xp,second); MnSymMatrix I(second,1);//Identity matrix diff --git a/smatrix/test/testOperations.cxx b/smatrix/test/testOperations.cxx index be886229a3f340d69f3bb1f78f2eb63a85648370..d1deeca31b1653f9a5896d54de65dec1db6600cd 100644 --- a/smatrix/test/testOperations.cxx +++ b/smatrix/test/testOperations.cxx @@ -796,8 +796,9 @@ int main(int argc , char *argv[] ) { NLOOP = 1000*NLOOP_MIN initValues(); - TEST(5) +// NLOOP = 50*NLOOP_MIN; +// TEST(30); #else NLOOP = 5000*NLOOP_MIN; initValues(); diff --git a/smatrix/test/testSMatrix.cxx b/smatrix/test/testSMatrix.cxx index 70b0b7fe0e1d1525ecb1d7aad12b9dd6583da1b8..50a45c741dfb4742bd7767026f1ab8a9bd2b5f8e 100644 --- a/smatrix/test/testSMatrix.cxx +++ b/smatrix/test/testSMatrix.cxx @@ -79,11 +79,11 @@ int test1() { //std::vector<float> vp(sp.begin(), sp.end() ); std::vector<float> vm(sm.begin(), sm.end() ); - //SVector<float, 2> sp2(vp.begin(),vp.end()); - //SVector<float, 2> sp2(vp.begin(),vp.size()); + SVector<float, 4> sp1(m,4); + SVector<float, 4> sp2(sm.begin(),sm.end()); SMatrix<float, 2,2> sm2(vm.begin(),vm.end()); - //if ( sp2 != sp) { cout << "Test STL interface for SVector failed" << endl; return -1; } + if ( sp1 != sp2) { cout << "Test STL interface for SVector failed" << endl; return -1; } if ( sm2 != sm) { cout << "Test STL interface for SMatrix failed" << endl; return -1; } @@ -137,7 +137,7 @@ int test3() { cout << "A: " << endl << A << endl; double det = 0.; - A.Sdet(det); + A.Det(det); cout << "Determinant: " << det << endl; // WARNING: A has changed!! cout << "A again: " << endl << A << endl; @@ -446,6 +446,24 @@ int test12() { double a = 3; std::cout << "S\n" << a * S << std::endl; + // test inversion + int ifail1 = 0; + //int ifail2 = 0; + SMatrix<double,2,2,MatRepSym<double,2> > Sinv1 = S.Inverse (ifail1); + //SMatrix<double,2,2,MatRepSym<double,2> > Sinv2 = S.Sinverse(ifail2); + std::cout << "Inverse: S-1 " << Sinv1 << "\nifail=" << ifail1 << std::endl; + //std::cout << "Sinverse: S-1" << Sinv2 << "\nifail=" << ifail2 << std::endl; + + SMatrix<double,2> IS1 = S*Sinv1; + //SMatrix<double,2> IS2 = S*Sinv2; + double d1 = std::sqrt( IS1(1,0)*IS1(1,0) + IS1(0,1)*IS1(0,1) ); + //double d2 = std::sqrt( IS2(1,0)*IS2(1,0) + IS2(0,1)*IS2(0,1) ); + + + iret |= compare( d1 < 1E-6,true,"inversion1" ); + //iret |= compare( d2 < 1E-6,true,"inversion2" ); + + SMatrix<double,2,3 > M1 = SMatrixIdentity(); M1(0,1) = 1; M1(1,0) = 1; M1(0,2) = 1; M1(1,2) = 1; SMatrix<double,2,3 > M2 = SMatrixIdentity(); @@ -881,6 +899,42 @@ int test16() { } +int test17() { + int iret =0; + // tets tensor product + SVector<double,2> v1(1,2); + SVector<double,3> v2(1,2,3); + + SMatrix<double,2,3> m = TensorProd(v1,v2); + std::cout << "Tensor Product \n" << m << std::endl; + + SVector<double,4> a1(2,-1,3,4); + SVector<double,4> a2(5,6,1,-2); + + SMatrix<double,4> A = TensorProd(a1,a2); + double r1 = Dot(a1, A * a2 ); + double r2 = Dot(a1, a1) * Dot(a2,a2 ); + iret |= compare(r1,r2,"tensor prod"); + + A = TensorProd(2.*a1,a2); + r1 = Dot(a1, A * a2 )/2; + r2 = Dot(a1, a1) * Dot(a2,a2 ); + iret |= compare(r1,r2,"tensor prod"); + + + A = TensorProd(a1,2*a2); + r1 = Dot(a1, A * a2 )/2; + r2 = Dot(a1, a1) * Dot(a2,a2 ); + iret |= compare(r1,r2,"tensor prod"); + + A = TensorProd(0.5*a1,2*a2); + r1 = Dot(a1, A * a2 ); + r2 = Dot(a1, a1) * Dot(a2,a2 ); + iret |= compare(r1,r2,"tensor prod"); + + return iret; +} + #define TEST(N) \ itest = N; \ @@ -909,6 +963,7 @@ int main() { TEST(14); TEST(15); TEST(16); + TEST(17);