#define RUN_ALL_POINTS //#define HAVE_CLHEP //#define DEBUG #include "Math/SVector.h" #include "Math/SMatrix.h" #include "TMatrixD.h" #include "TVectorD.h" #include "TFile.h" #include "TSystem.h" #include "TROOT.h" #include "TRandom3.h" #include "TStopwatch.h" #include #include //#undef HAVE_CLHEP #ifdef HAVE_CLHEP #include "CLHEP/Matrix/SymMatrix.h" #include "CLHEP/Matrix/Matrix.h" #include "CLHEP/Matrix/Vector.h" #endif #define NITER 1 // number of iterations #define NLOOP 1000000 // number of time the test is repeted template class TestRunner { public: // kalman test with normal matrices from SMatrix int test_smatrix_kalman() ; // kalman test with sym matrices from SMatrix int test_smatrix_sym_kalman(); // kalman test with matrices (normal and sym) from TMatrix int test_tmatrix_kalman(); #ifdef HAVE_CLHEP // test with CLHEP matrix int test_clhep_kalman(); #endif // run the all tests int run() { int iret = 0; iret |= test_smatrix_sym_kalman(); iret |= test_smatrix_kalman(); iret |= test_tmatrix_kalman(); #ifdef HAVE_CLHEP iret |= test_clhep_kalman(); #endif std::cout << "\n\n"; return iret; } private: double fX2sum; double fC2sum; }; #define TR(N1,N2) \ { TestRunner tr; if (tr.run()) return -1; } int runTest() { #ifndef RUN_ALL_POINTS TR(2,5) //TR(2,10) #else TR(2,2) TR(2,3) TR(2,4) TR(2,5) TR(2,6) TR(2,7) TR(2,8) TR(3,2) TR(3,3) TR(3,4) TR(3,5) TR(3,6) TR(3,7) TR(3,8) TR(4,2) TR(4,3) TR(4,4) TR(4,5) TR(4,6) TR(4,7) TR(4,8) TR(5,2) TR(5,3) TR(5,4) TR(5,5) TR(5,6) TR(5,7) TR(5,8) TR(6,2) TR(6,3) TR(6,4) TR(6,5) TR(6,6) TR(6,7) TR(6,8) TR(7,2) TR(7,3) TR(7,4) TR(7,5) TR(7,6) TR(7,7) TR(7,8) TR(8,2) TR(8,3) TR(8,4) TR(8,5) TR(8,6) TR(8,7) TR(8,8) TR(9,2) TR(9,3) TR(9,4) TR(9,5) TR(9,6) TR(9,7) TR(9,8) TR(10,2) TR(10,3) TR(10,4) TR(10,5) TR(10,6) TR(10,7) TR(10,8) #endif return 0; } // utility functions to fill matrices and vectors with random data template void fillRandomVec(TRandom & r, V & v, unsigned int len, unsigned int start = 0, double offset = 1) { for(unsigned int i = start; i < len+start; ++i) v[i] = r.Rndm() + offset; } template void fillRandomMat(TRandom & r, M & m, unsigned int first, unsigned int second, unsigned int start = 0, double offset = 1) { for(unsigned int i = start; i < first+start; ++i) for(unsigned int j = start; j < second+start; ++j) m(i,j) = r.Rndm() + offset; } template void fillRandomSym(TRandom & r, M & m, unsigned int first, unsigned int start = 0, double offset = 1) { for(unsigned int i = start; i < first+start; ++i) { for(unsigned int j = i; j < first+start; ++j) { if ( i != j ) { m(i,j) = r.Rndm() + offset; m(j,i) = m(i,j); } else // add extra offset to make no singular when inverting m(i,i) = r.Rndm() + 3*offset; } } } // simple class to measure time void printTime(TStopwatch & time, std::string s) { int pr = std::cout.precision(4); std::cout << std::setw(12) << s << "\t" << " Real time = " << time.RealTime() << "\t(sec)\tCPU time = " << time.CpuTime() << "\t(sec)" << std::endl; std::cout.precision(pr); } // reference times for sizes <=6 and > 6 on Linux slc3 P4 3Ghz ("SMatrix","SMatrix_sym","TMatrix") 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 // class to hold time results class TimeReport { // typedef std::map > > ResultTable; typedef std::map a; typedef ROOT::Math::SMatrix M; typedef std::map< std::string, M > ResultTable; public: TimeReport() {} ~TimeReport() { /*print(); */ } // set timing point void Set(const std::string & name, int dim1, int dim2 ) { fDim1 = dim1; fDim2 = dim2; fName = name; // insert in map if not existing if (fResult1.find(name) == fResult1.end() ) fResult1.insert(ResultTable::value_type(name, M() ) ); if (fResult2.find(name) == fResult2.end() ) fResult2.insert(ResultTable::value_type(name, M() ) ); } std::string name() const { return fName; } void report(double rt, double ct) { fResult1[fName](fDim1-2,fDim2-2) = rt; fResult2[fName](fDim1-2,fDim2-2) = ct; } double smallSum(const M & m, int cut = 6) { // sum for sizes <= cut double sum = 0; for (int i = 0; i cut double sum = 0; for (int i = 0; i cut-2 || j > cut-2) sum+= m(i,j); return sum; } void print(std::ostream & os) { std::map r1; std::map r2; os << "Real time results " << std::endl; for (ResultTable::iterator itr = fResult1.begin(); itr != fResult1.end(); ++itr) { std::string type = itr->first; os << " Results for " << type << std::endl; os << "\n" << itr->second << std::endl << std::endl; r1[type] = smallSum(itr->second); r2[type] = largeSum(itr->second); os << "\nTotal for N1,N2 <= 6 : " << r1[type] << std::endl; os << "\nTotal for N1,N2 > 6 : " << r2[type] << std::endl; } os << "\n\nCPU time results " << std::endl; for (ResultTable::iterator itr = fResult2.begin(); itr != fResult2.end(); ++itr) { os << " Results for " << itr->first << std::endl; os << "\n" << itr->second << std::endl << std::endl; os << "\nTotal for N1,N2 <= 6 : " << smallSum(itr->second) << std::endl; os << "\nTotal for N1,N2 > 6 : " << largeSum(itr->second) << std::endl; } // print summary os << "\n\n****************************************************************************\n"; os << "Root version: " << gROOT->GetVersion() << " " << gROOT->GetVersionDate() << "/" << gROOT->GetVersionTime() << std::endl; os << "****************************************************************************\n"; os << "\n\t ROOTMARKS for N1,N2 <= 6 \n\n"; int j = 0; os.setf(std::ios::right,std::ios::adjustfield); for (std::map::iterator i = r1.begin(); i != r1.end(); ++i) { std::string type = i->first; os << std::setw(12) << type << "\t=\t" << refTime1[j]*800/r1[type] << std::endl; j++; } os << "\n\t ROOTMARKS for N1,N2 > 6 \n\n"; j = 0; for (std::map::iterator i = r1.begin(); i != r1.end(); ++i) { std::string type = i->first; os << std::setw(12) << type << "\t=\t" << refTime2[j]*800/r2[type] << std::endl; j++; } } void save(const std::string & fileName) { TFile file(fileName.c_str(),"RECREATE"); gSystem->Load("libSmatrix"); // save RealTime results for (ResultTable::iterator itr = fResult1.begin(); itr != fResult1.end(); ++itr) { int ret = file.WriteObject(&(itr->second),(itr->first).c_str() ); if (ret ==0) std::cerr << "==> Error saving results in ROOT file " << fileName << std::endl; } // save CPU time results for (ResultTable::iterator itr = fResult2.begin(); itr != fResult2.end(); ++itr) { std::string typeName = itr->first + "_2"; int ret = file.WriteObject(&(itr->second), typeName.c_str() ); if (ret ==0) std::cerr << "==> Error saving results in ROOT file " << fileName << std::endl; } file.Close(); } private: int fDim1; int fDim2; std::string fName; ResultTable fResult1; ResultTable fResult2; }; //global instance of time report TimeReport gReporter; class TestTimer { public: // TestTimer(const std::string & s = "") : // fName(s), fTime(0), fRep(0) // { // fWatch.Start(); // } TestTimer(TimeReport & r ) : fTime(0), fRep(&r) { fName = fRep->name(); fWatch.Start(); } TestTimer(double & t, const std::string & s = "") : fName(s), fTime(&t), fRep(0) { fWatch.Start(); } ~TestTimer() { fWatch.Stop(); printTime(fWatch,fName); if (fRep) fRep->report( fWatch.RealTime(), fWatch.CpuTime() ); if (fTime) *fTime += fWatch.RealTime(); } private: std::string fName; double * fTime; TStopwatch fWatch; TimeReport * fRep; }; template int TestRunner::test_smatrix_kalman() { gReporter.Set("SMatrix",NDIM1,NDIM2); // need to write explicitly the dimensions typedef ROOT::Math::SMatrix MnMatrixNN; typedef ROOT::Math::SMatrix MnMatrixMM; typedef ROOT::Math::SMatrix MnMatrixNM; typedef ROOT::Math::SMatrix MnMatrixMN; typedef ROOT::Math::SMatrix MnSymMatrixNN; typedef ROOT::Math::SMatrix MnSymMatrixMM; typedef ROOT::Math::SVector MnVectorN; typedef ROOT::Math::SVector MnVectorM; int first = NDIM1; //Can change the size of the matrices int second = NDIM2; std::cout << "****************************************************************************\n"; std::cout << "\t\tSMatrix kalman test " << first << " x " << second << std::endl; std::cout << "****************************************************************************\n"; int npass = NITER; TRandom3 r(111); double x2sum = 0, c2sum = 0; for (int k = 0; k < npass; k++) { MnMatrixNM H; MnMatrixMN K0; MnSymMatrixMM Cp; MnSymMatrixNN V; MnVectorN m; MnVectorM xp; { // fill matrices with random data fillRandomMat(r,H,first,second); fillRandomMat(r,K0,second,first); fillRandomSym(r,Cp,second); fillRandomSym(r,V,first); fillRandomVec(r,m,first); fillRandomVec(r,xp,second); } MnSymMatrixMM I; for(int i = 0; i < second; i++) I(i,i) = 1; #ifdef DEBUG std::cout << "pass " << k << std::endl; if (k == 0) { std::cout << " K0 = " << K0 << std::endl; std::cout << " H = " << K0 << std::endl; std::cout << " Cp = " << Cp << std::endl; std::cout << " V = " << V << std::endl; std::cout << " m = " << m << std::endl; std::cout << " xp = " << xp << std::endl; } #endif { double x2 = 0,c2 = 0; TestTimer t(gReporter); MnVectorM x; MnMatrixMN tmp; MnSymMatrixNN Rinv; MnMatrixMN K; MnSymMatrixMM C; MnVectorN vtmp1; MnVectorN vtmp; for (int l = 0; l < NLOOP; l++) { vtmp1 = H*xp -m; //x = xp + K0 * (m- H * xp); x = xp - K0 * vtmp1; tmp = Cp * Transpose(H); Rinv = V; Rinv += H * tmp; bool test = Rinv.Invert(); if(!test) { std::cout<<"inversion failed" < MnMatrixNN; typedef ROOT::Math::SMatrix MnMatrixMM; typedef ROOT::Math::SMatrix MnMatrixNM; typedef ROOT::Math::SMatrix MnMatrixMN; typedef ROOT::Math::SMatrix > MnSymMatrixNN; typedef ROOT::Math::SMatrix > MnSymMatrixMM; typedef ROOT::Math::SVector MnVectorN; typedef ROOT::Math::SVector MnVectorM; typedef ROOT::Math::SVector MnVectorN2; typedef ROOT::Math::SVector MnVectorM2; int first = NDIM1; //Can change the size of the matrices int second = NDIM2; std::cout << "****************************************************************************\n"; std::cout << "\t\tSMatrix_Sym kalman test " << first << " x " << second << std::endl; std::cout << "****************************************************************************\n"; int npass = NITER; TRandom3 r(111); double x2sum = 0, c2sum = 0; for (int k = 0; k < npass; k++) { MnMatrixNM H; MnMatrixMN K0; MnSymMatrixMM Cp; MnSymMatrixNN V; MnVectorN m; MnVectorM xp; { // fill matrices with random data fillRandomMat(r,H,first,second); fillRandomMat(r,K0,second,first); fillRandomSym(r,Cp,second); fillRandomSym(r,V,first); fillRandomVec(r,m,first); fillRandomVec(r,xp,second); } MnSymMatrixMM I; for(int i = 0; i < second; i++) I(i,i) = 1; #ifdef DEBUG std::cout << "pass " << k << std::endl; if (k == 0) { std::cout << " K0 = " << K0 << std::endl; std::cout << " H = " << K0 << std::endl; std::cout << " Cp = " << Cp << std::endl; std::cout << " V = " << V << std::endl; std::cout << " m = " << m << std::endl; std::cout << " xp = " << xp << std::endl; } #endif { double x2 = 0,c2 = 0; TestTimer t(gReporter); MnVectorM x; MnSymMatrixNN RinvSym; MnMatrixMN K; MnSymMatrixMM C; MnSymMatrixMM Ctmp; MnVectorN vtmp1; MnVectorN vtmp; #define OPTIMIZED_SMATRIX_SYM #ifdef OPTIMIZED_SMATRIX_SYM MnMatrixMN tmp; #endif for (int l = 0; l < NLOOP; l++) { #ifdef OPTIMIZED_SMATRIX_SYM vtmp1 = H*xp -m; //x = xp + K0 * (m- H * xp); x = xp - K0 * vtmp1; tmp = Cp * Transpose(H); // we are sure that H*tmp result is symmetric ROOT::Math::AssignSym::Evaluate(RinvSym,H*tmp); RinvSym += V; bool test = RinvSym.Invert(); if(!test) { std::cout<<"inversion failed" < MnMatrix; //typedef HepSymMatrix MnSymMatrixHep; int first = NDIM1; //Can change the size of the matrices int second = NDIM2; std::cout << "****************************************************************************\n"; std::cout << "\t\tTMatrix Kalman test " << first << " x " << second << std::endl; std::cout << "****************************************************************************\n"; int npass = NITER; TRandom3 r(111); double x2sum = 0,c2sum = 0; for (int k = 0; k < npass; k++) { MnMatrix H(first,second); MnMatrix K0(second,first); MnMatrix Cp(second,second); MnMatrix V(first,first); MnVector m(first); MnVector xp(second); // fill matrices with random data fillRandomMat(r,H,first,second); fillRandomMat(r,K0,second,first); fillRandomSym(r,Cp,second); fillRandomSym(r,V,first); fillRandomVec(r,m,first); fillRandomVec(r,xp,second); MnMatrix I(second,second);//Identity matrix for (int i = 0; i < second; i++) for(int j = 0; j MnMatrix; //typedef HepSymMatrix MnSymMatrixHep; int first = NDIM1; //Can change the size of the matrices int second = NDIM2; std::cout << "****************************************************************************\n"; std::cout << " CLHEP Kalman test " << first << " x " << second << std::endl; std::cout << "****************************************************************************\n"; int npass = NITER; TRandom3 r(111); double x2sum = 0,c2sum = 0; for (int k = 0; k < npass; k++) { // in CLHEP index starts from 1 MnMatrix H(first,second); MnMatrix K0(second,first); MnMatrix Cp(second,second); MnMatrix V(first,first); MnVector m(first); MnVector xp(second); // fill matrices with random data fillRandomMat(r,H,first,second,1); fillRandomMat(r,K0,second,first,1); fillRandomSym(r,Cp,second,1); fillRandomSym(r,V,first,1); fillRandomVec(r,m,first); fillRandomVec(r,xp,second); MnSymMatrix I(second,1);//Identity matrix { double x2 = 0,c2 = 0; MnVector x(second); MnMatrix Rinv(first,first); MnSymMatrix RinvSym(first); MnMatrix K(second,first); MnSymMatrix C(second); MnVector vtmp1(first); MnMatrix tmp(second,first); TestTimer t(gReporter); int ifail; for (Int_t l = 0; l < NLOOP; l++) { vtmp1 = H*xp -m; //x = xp + K0 * (m- H * xp); x = xp - K0 * vtmp1; tmp = Cp * H.T(); Rinv = V; Rinv += H * tmp; RinvSym.assign(Rinv); RinvSym.invert(ifail); if (ifail !=0) { std::cout << "Error inverting Rinv" << std::endl; break; } K = tmp*RinvSym; //C.assign( (I-K*H)*Cp); //C = (I-K*H)*Cp; C.assign( (I-K*H)*Cp ); x2= RinvSym.similarity(vtmp1); if(ifail!=0) { std::cout << "Error inverting Rinv" << std::endl; break; } } x2sum += x2; c2 = 0; for (unsigned int i=1; i<=NDIM2; ++i) for (unsigned int j=1; j<=NDIM2; ++j) c2 += C(i,j); c2sum += c2; } // } } //tr.dump(); //std::cout << "x2sum = " << x2sum << "\tc2sum = " << c2sum << std::endl; int iret = 0; double d = std::abs(x2sum-fX2sum); if ( d > 1.E-6 * fX2sum ) { std::cout << "ERROR: difference found in x2sum = " << x2sum << "\tref = " << fX2sum << "\tdiff = " << d << std::endl; iret = 1; } d = std::abs(c2sum-fC2sum); if ( d > 1.E-6 * fC2sum ) { std::cout << "ERROR: difference found in c2sum = " << c2sum << "\tref = " << fC2sum << "\tdiff = " << d << std::endl; iret = 1; } return iret; } #endif int main(int argc, char *argv[]) { if (runTest() ) { std::cout << "\nERROR - stressKalman FAILED - exit!" << std::endl ; return -1; }; gReporter.print(std::cout); std::string fname = "kalman"; if (argc > 1) { std::string platf(argv[1]); fname = fname + "_" + platf; } gReporter.save(fname+".root"); return 0; }