#include "TBenchmark.h" #include "Math/GoFTest.h" #include "Math/Functor.h" #include "TROOT.h" #include "TSystem.h" #include "TStopwatch.h" #include "Math/GSLRndmEngines.h" #if not defined(__CINT__) #include "Math/Random.h" #endif #include "TRandom3.h" #include #include /*N.B.: The tests' expected values (expectedDn and expectedA2) were computed on Pcphsft54.cern.ch i386 GNU/Linux computer (slc4_ia32_gcc34) */ struct GoFTStress { static enum EDebugLevelTypes { kNoDebug, // no test results printing kBasicDebug, // prints either "OK" or "FAIL" test results kStandardDebug, // prints summarized test results } fgDebugLevel; Int_t RunTests() { Int_t result = 0; result += UnitTest1(); result += UnitTest2(); result += UnitTest3(); result += UnitTest4(); result += UnitTest5(); result += UnitTest6(); result += UnitTest7(); return result; } void PrintBenchmark() { if (fgDebugLevel == kNoDebug) { return; } //Print table with results Bool_t UNIX = strcmp(gSystem->GetName(), "Unix") == 0; printf("******************************************************************\n"); if (UNIX) { FILE *fp = gSystem->OpenPipe("uname -a", "r"); Char_t line[60]; fgets(line,60,fp); line[59] = 0; printf("* SYS: %s\n",line); gSystem->ClosePipe(fp); } else { const Char_t *os = gSystem->Getenv("OS"); if (!os) { printf("* SYS: Windows 95\n"); } else { printf("* SYS: %s %s \n",os,gSystem->Getenv("PROCESSOR_IDENTIFIER")); } } printf("*****************************************************************************************\n"); gBenchmark->Print("GoFTestStress"); #ifdef __CINT__ Double_t reftime = 0.02 ; // slc4rabacal interpreted (CPU time taken to run complete tests with ACLiC) #else Double_t reftime = 0.04; // slc4rabacal compiled (CPU time taken to run complete tests) #endif Double_t rootmarks = 800. * reftime / gBenchmark->GetCpuTime("GoFTestStress"); printf("*****************************************************************************************\n"); printf("* ROOTMARKS = %6.1f * Root%-8s %d/%d\n", rootmarks, gROOT->GetVersion(), gROOT->GetVersionDate(),gROOT->GetVersionTime()); printf("*****************************************************************************************\n"); } private: Int_t UnitTest1() { std::cout << "UNIT TEST 1" << std::endl; UInt_t nsmps = 2; const UInt_t smpSize1 = 71; const UInt_t smpSize2 = 135; /* Data set adapted from the paper (1) "K-Sample Anderson-Darling Tests of Fit for continuous and discrete cases" by Scholz and Stephens */ const Double_t smp1[smpSize1] = {194, 15, 41, 29, 33, 181, 413, 14, 58, 37, 100, 65, 9, 169, 447, 18, 4, 36, 201, 118, 34, 31, 18, 18, 67, 57, 62, 7, 22, 34, 90, 10, 60, 186, 61, 49, 14, 24, 56, 20, 79, 84, 44, 59, 29, 118, 25, 156, 310, 76, 26, 44, 23, 62, 130, 208, 70, 101, 208, 74, 57, 48, 29, 502, 12, 70, 21, 29, 386, 59, 27}; const Double_t smp2[smpSize2] = {55, 320, 56, 104, 220, 239, 47, 246, 176, 182, 33, 23, 261, 87, 7, 120, 14, 62, 47, 225, 71, 246, 21, 42, 20, 5, 12, 120, 11, 3, 14, 71, 11, 14, 11, 16, 90, 1, 16, 52, 95, 97, 51, 11, 4, 141, 18, 142, 68, 77, 80, 1, 16, 106, 206, 82, 54, 31, 216, 46, 111, 39, 63, 18, 191, 18, 163, 24, 50, 44, 102, 72, 22, 39, 3, 15, 197, 188, 79, 88, 46, 5, 5, 36, 22, 139, 210, 97, 30, 23, 13, 14, 359, 9, 12, 270, 603, 3, 104, 2, 438, 50, 254, 5, 283, 35, 12, 487, 18, 100, 7, 98, 5, 85, 91, 43, 230, 3, 130, 102, 209, 14, 57, 54, 32, 67, 59, 134, 152, 27, 14, 230, 66, 61, 34}; ROOT::Math::GoFTest* goft = new ROOT::Math::GoFTest( smpSize1, smp1, smpSize2, smp2 ); Double_t A2 = goft->AndersonDarling2SamplesTest("t"); // standartized A2_akN // Double_t pvalueAD = goft->AndersonDarling2SamplesTest(); Double_t pvalueAD = (*goft)(ROOT::Math::GoFTest::kAD2s); Double_t expectedA2_akN = 1.58334 ; // A2_akN in (1) Double_t sigmaN = 0.754539; // sigmaN in (1) Double_t zScore = 0.773108; // zScore in (1) Int_t result = PrintResultAD2Samples(nsmps, A2, expectedA2_akN, sigmaN, zScore, pvalueAD); // Double_t Dn = goft->KolmogorovSmirnov2SamplesTest("t"); // standartized A2_akN Double_t Dn = (*goft)(ROOT::Math::GoFTest::kKS2s, "t"); Double_t pvalueKS = goft->KolmogorovSmirnov2SamplesTest(); Double_t expectedDn = 0.139176; result += PrintResultKS(nsmps, Dn, expectedDn, pvalueKS); delete goft; return result; } Int_t UnitTest2() { std::cout << "UNIT TEST 2" << std::endl; const UInt_t nsmps = 2; const UInt_t smpSize = 16; /* Data sets adapted from the paper (1) "K-Sample Anderson-Darling Tests of Fit for continuous and discrete cases" by Scholz and Stephens */ const Double_t smp1[smpSize] = {38.7, 41.5, 43.8, 44.5, 45.5, 46.0, 47.7, 58.0, 39.2, 39.3, 39.7, 41.4, 41.8, 42.9, 43.3, 45.8}; const Double_t smp2[smpSize] = {34.0, 35.0, 39.0, 40.0, 43.0, 43.0, 44.0, 45.0, 34.0, 34.8, 34.8, 35.4, 37.2, 37.8, 41.2, 42.8}; ROOT::Math::GoFTest* goft = new ROOT::Math::GoFTest( smpSize, smp1, smpSize, smp2 ); // Double_t A2 = goft->AndersonDarling2SamplesTest("t"); // standartized A2_akN Double_t A2 = (*goft)(ROOT::Math::GoFTest::kAD2s, "t"); Double_t pvalueAD = goft->AndersonDarling2SamplesTest(); Double_t expectedA2_akN = 4.5735; // unstandardized A2_akN in (1) Double_t sigmaN = 0.719388; // sigmaN in (1) Double_t zScore = 4.96748; // zScore in (1) Int_t result = PrintResultAD2Samples(nsmps, A2, expectedA2_akN, sigmaN, zScore, pvalueAD); Double_t Dn = goft->KolmogorovSmirnov2SamplesTest("t"); // standartized A2_akN // Double_t pvalueKS = goft->KolmogorovSmirnov2SamplesTest(); Double_t pvalueKS = (*goft)(ROOT::Math::GoFTest::kKS2s); Double_t expectedDn = 0.5; result += PrintResultKS(nsmps, Dn, expectedDn, pvalueKS); delete goft; return result; } Int_t UnitTest3() { std::cout << "UNIT TEST 3" << std::endl; UInt_t nEvents = 1000; UInt_t nsmps = 1; ROOT::Math::Random r; Double_t* sample = new Double_t[nEvents]; for (UInt_t i = 0; i < nEvents; ++i) { Double_t data = r.LogNormal(5.0, 2.0); sample[i] = data; assert(sample[i] == data); } ROOT::Math::GoFTest* goft = new ROOT::Math::GoFTest(nEvents, sample, ROOT::Math::GoFTest::kLogNormal); if (GoFTStress::fgDebugLevel == GoFTStress::kStandardDebug) std::cout << "LogNormal fitting" << std::endl; // Double_t A2 = goft->AndersonDarlingTest("t"); Double_t A2 = goft->operator()(ROOT::Math::GoFTest::kAD, "t"); Double_t pvalueAD = goft->AndersonDarlingTest(); Double_t expectedA2 = 0.422771; Int_t result = PrintResultAD1Sample(A2, expectedA2, pvalueAD); Double_t Dn = goft->KolmogorovSmirnovTest("t"); // Double_t pvalueKS = goft->KolmogorovSmirnovTest(); Double_t pvalueKS = goft->operator()(ROOT::Math::GoFTest::kKS); Double_t expectedDn = 0.0204916; result += PrintResultKS(nsmps, Dn, expectedDn, pvalueKS); delete goft; return result; } Int_t UnitTest4() { std::cout << "UNIT TEST 4" << std::endl; UInt_t nEvents = 1000; UInt_t nsmps = 1; TRandom3 r; Double_t* sample = new Double_t[nEvents]; for (UInt_t i = 0; i < nEvents; ++i) { Double_t data = r.Exp(1.54); sample[i] = data; assert(sample[i] == data); } ROOT::Math::GoFTest* goft = new ROOT::Math::GoFTest(nEvents, sample, ROOT::Math::GoFTest::kExponential); if (GoFTStress::fgDebugLevel == GoFTStress::kStandardDebug) std::cout << "**Exponential fitting**" << std::endl; Double_t A2 = goft->AndersonDarlingTest("t"); // Double_t pvalueAD = goft->AndersonDarlingTest(); Double_t pvalueAD = goft->operator()(); Double_t expectedA2 = 0.521153; Int_t result = PrintResultAD1Sample(A2, expectedA2, pvalueAD); // Double_t Dn = goft->KolmogorovSmirnovTest("t"); Double_t Dn = goft->operator()(ROOT::Math::GoFTest::kKS, "t"); Double_t pvalueKS = goft->KolmogorovSmirnovTest(); Double_t expectedDn = 0.0218148; result += PrintResultKS(nsmps, Dn, expectedDn, pvalueKS); delete goft; return result; } Int_t UnitTest5() { std::cout << "UNIT TEST 5" << std::endl; UInt_t nEvents = 1000; UInt_t nsmps = 1; TRandom3 r; Double_t* sample = new Double_t[nEvents]; for (UInt_t i = 0; i < nEvents; ++i) { Double_t data = r.Gaus(300, 50); sample[i] = data; assert(sample[i] == data); } ROOT::Math::GoFTest* goft = new ROOT::Math::GoFTest(nEvents, sample); goft->SetDistribution(ROOT::Math::GoFTest::kGaussian); if (GoFTStress::fgDebugLevel == GoFTStress::kStandardDebug) std::cout << "**Gaussian fitting**" << std::endl; Double_t A2 = goft->AndersonDarlingTest("t"); Double_t pvalueAD = goft->AndersonDarlingTest(); Double_t expectedA2 = 0.441755; Int_t result = PrintResultAD1Sample(A2, expectedA2, pvalueAD); Double_t Dn = goft->KolmogorovSmirnovTest("t"); Double_t pvalueKS = goft->KolmogorovSmirnovTest(); Double_t expectedDn = 0.0282508; result += PrintResultKS(nsmps, Dn, expectedDn, pvalueKS); delete goft; return result; } Int_t UnitTest6() { std::cout << "UNIT TEST 6" << std::endl; UInt_t nEvents = 1000; UInt_t nsmps = 1; TRandom3 r; Double_t* sample = new Double_t[nEvents]; for (UInt_t i = 0; i < nEvents; ++i) { Double_t data = r.Landau(); sample[i] = data; assert(sample[i] == data); } ROOT::Math::Functor1D userCdf(&TMath::LandauI); ROOT::Math::GoFTest* goft = new ROOT::Math::GoFTest(nEvents, sample, userCdf, ROOT::Math::GoFTest::kCDF); if (GoFTStress::fgDebugLevel == GoFTStress::kStandardDebug) std::cout << "**Landau fitting**" << std::endl; Double_t A2 = goft->AndersonDarlingTest("t"); Double_t pvalueAD = goft->AndersonDarlingTest(); Double_t expectedA2 = 0.544658; Int_t result = PrintResultAD1Sample(A2, expectedA2, pvalueAD); Double_t Dn = goft->KolmogorovSmirnovTest("t"); Double_t pvalueKS = goft->KolmogorovSmirnovTest(); Double_t expectedDn = 0.0203432; result += PrintResultKS(nsmps, Dn, expectedDn, pvalueKS); delete goft; return result; } Int_t UnitTest7() { std::cout << "UNIT TEST 7" << std::endl; UInt_t nEvents = 1000; UInt_t nsmps = 1; TRandom3 r; Double_t* sample = new Double_t[nEvents]; for (UInt_t i = 0; i < nEvents; ++i) { Double_t data = r.Landau(); sample[i] = data; } // need to specify min and max otherwise pdf does not converge ROOT::Math::GoFTest* goft = new ROOT::Math::GoFTest(nEvents, sample); ROOT::Math::Functor1D userPdf(&TMath::Landau); // need to use a reasanble range for the Landau // but must be bigger than xmin and xmax double xmin = 3*TMath::MinElement(nEvents, sample); double xmax = 3*TMath::MaxElement(nEvents, sample); if (GoFTStress::fgDebugLevel == GoFTStress::kStandardDebug) std::cout << "**Landau fitting**" << " in [ " << xmin << " , " << xmax << " ]" << std::endl; goft->SetUserDistribution(userPdf,ROOT::Math::GoFTest::kPDF, xmin, xmax); Double_t A2 = goft->AndersonDarlingTest("t"); Double_t pvalueAD = goft->AndersonDarlingTest(); Double_t expectedA2 = 0.544658; // use larger tolerance due to truncation error of Landau Int_t result = PrintResultAD1Sample(A2, expectedA2, pvalueAD,0.002); Double_t Dn = goft->KolmogorovSmirnovTest("t"); Double_t pvalueKS = goft->KolmogorovSmirnovTest(); Double_t expectedDn = 0.0203432; result += PrintResultKS(nsmps, Dn, expectedDn, pvalueKS,0.001); delete goft; return result; } Int_t PrintResultAD2Samples(UInt_t nsmps, Double_t A2, Double_t expectedA2_akN, Double_t sigmaN, Double_t zScore, Double_t pvalue, Double_t limit = 0.0001) { Double_t A2_akN = A2 * sigmaN + (nsmps - 1); if (GoFTStress::fgDebugLevel == GoFTStress::kStandardDebug) { std::cout << "Anderson-Darling 2-Samples Test" << std::endl; std::cout << "pvalue = " << pvalue << std::endl; std::cout << "zScore = " << zScore << std::endl; std::cout << "Expected A2 value = " << A2 << std::endl; std::cout << "A2_akN = " << A2_akN << std::endl; std::cout << "Expected A2_akN value = " << expectedA2_akN << std::endl; } if (TMath::Abs(A2_akN - expectedA2_akN) < limit * expectedA2_akN || TMath::Abs(A2 - zScore) < limit * zScore) { if (GoFTStress::fgDebugLevel >= GoFTStress::kBasicDebug) std::cout << "+++++++ TEST OK +++++++ \n" << std::endl; return EXIT_SUCCESS; } else { if (GoFTStress::fgDebugLevel >= GoFTStress::kBasicDebug) std::cout << "------- TEST FAIL ------- \n" << std::endl; return EXIT_FAILURE; } } Int_t PrintResultAD1Sample(Double_t A2, Double_t expectedA2, Double_t pvalue, Double_t limit = 0.0001) { if (GoFTStress::fgDebugLevel == GoFTStress::kStandardDebug) { std::cout << "Anderson-Darling 1-Sample Test" << std::endl; std::cout << "pvalue = " << pvalue << std::endl; std::cout << "A2 value = " << A2 << std::endl; std::cout << "Expected A2 value = " << expectedA2 << std::endl; } if (TMath::Abs(A2 - expectedA2) < limit * expectedA2) { if (GoFTStress::fgDebugLevel >= GoFTStress::kBasicDebug) std::cout << "+++++++ TEST OK +++++++ \n" << std::endl; return EXIT_SUCCESS; } else { if (GoFTStress::fgDebugLevel >= GoFTStress::kBasicDebug) std::cout << "------- TEST FAIL ------- \n" << std::endl; return EXIT_FAILURE; } } Int_t PrintResultKS(UInt_t nsmps, Double_t Dn, Double_t expectedDn, Double_t pvalue, Double_t limit = 0.0001) { if (GoFTStress::fgDebugLevel == GoFTStress::kStandardDebug) { std::cout << "Kolmogorov-Smirnov "<< nsmps << "-Samples Test" << std::endl; std::cout << "pvalue = " << pvalue << std::endl; std::cout << "Dn value = " << Dn << std::endl; std::cout << "Expected Dn value = " << expectedDn << std::endl; } if (TMath::Abs(Dn - expectedDn) < limit * expectedDn) { if (GoFTStress::fgDebugLevel >= GoFTStress::kBasicDebug) std::cout << "+++++++ TEST OK +++++++ \n" << std::endl; return EXIT_SUCCESS; } else { if (GoFTStress::fgDebugLevel >= GoFTStress::kBasicDebug) std::cout << "------- TEST FAIL ------- \n" << std::endl; return EXIT_FAILURE; } } }; #ifdef __MAKECINT__ #pragma link C++ class GoFTStress-; #endif GoFTStress::EDebugLevelTypes GoFTStress::fgDebugLevel; Int_t RunTests(Int_t argc, Char_t* argv[]) { Int_t result = 0; Bool_t validOption(kFALSE); if (argc == 1) { GoFTStress::fgDebugLevel = GoFTStress::kBasicDebug; validOption = kTRUE; } else if (argc == 3 && strcmp(argv[1], "--o") == 0) { if (strcmp(argv[2], "0") == 0 || strcmp(argv[2], "no-debug") == 0) { GoFTStress::fgDebugLevel = GoFTStress::kNoDebug; validOption = kTRUE; } else if (strcmp(argv[2], "1") == 0 || strcmp(argv[2], "basic-debug") == 0) { GoFTStress::fgDebugLevel = GoFTStress::kBasicDebug; validOption = kTRUE; std::cout << "Debug level: basic." << std::endl; } else if (strcmp(argv[2], "2") == 0 || strcmp(argv[2], "standard-debug") == 0) { GoFTStress::fgDebugLevel = GoFTStress::kStandardDebug; validOption = kTRUE; std::cout << "Debug level: standard." << std::endl; } else if (strcmp(argv[2], "help") == 0) { std::cout << "Showing help: " << std::endl; } } if (!validOption) { std::cout << "Please type just one of the following debug levels in either formats preceded by \"--o\":" << std::endl; std::cout << "a) no-debug(0) [no test results printing]" << std::endl; std::cout << "b) basic-debug(1) [prints either \"OK\" or \"FAIL\" test results]" << std::endl; std::cout << "c) standard-debug(2) [prints summarized test results]" << std::endl; return 0; } if (GoFTStress::fgDebugLevel >= GoFTStress::kBasicDebug) { std::cout << "*****************************************************************************************" << std::endl; std::cout << "* Goodness of Fit Test STRESS suite *" <Start("GoFTestStress"); GoFTStress* goftStressTest = new GoFTStress; result = goftStressTest->RunTests(); gBenchmark->Stop("GoFTestStress"); goftStressTest->PrintBenchmark(); delete goftStressTest; delete gBenchmark; return result; } Int_t stressGoFTest(Int_t argc = 1 , Char_t* argv[] = 0) { return RunTests(argc, argv); } #if not defined(__CINT__) && not defined(__MAKECINT__) Int_t main(Int_t argc, Char_t* argv[]) { return RunTests(argc, argv); } #endif