// Mantid Repository : https://github.com/mantidproject/mantid // // Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI, // NScD Oak Ridge National Laboratory, European Spallation Source, // Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS // SPDX - License - Identifier: GPL - 3.0 + #pragma once #include "MantidKernel/Statistics.h" #include #include #include #include #include using namespace Mantid::Kernel; using std::string; using std::vector; class StatisticsTest : public CxxTest::TestSuite { public: void test_Doubles_And_Default_Flags_Calculates_All_Stats() { vector data; data.emplace_back(17.2); data.emplace_back(18.1); data.emplace_back(16.5); data.emplace_back(18.3); data.emplace_back(12.6); Statistics stats = getStatistics(data); TS_ASSERT_EQUALS(stats.mean, 16.54); TS_ASSERT_DELTA(stats.standard_deviation, 2.0732, 0.0001); TS_ASSERT_EQUALS(stats.minimum, 12.6); TS_ASSERT_EQUALS(stats.maximum, 18.3); TS_ASSERT_EQUALS(stats.median, 17.2); } void test_Doubles_With_Sorted_Data() { vector data; data.emplace_back(17.2); data.emplace_back(18.1); data.emplace_back(16.5); data.emplace_back(18.3); data.emplace_back(12.6); sort(data.begin(), data.end()); Statistics stats = getStatistics(data, (StatOptions::Median | StatOptions::SortedData)); TS_ASSERT(std::isnan(stats.mean)); TS_ASSERT(std::isnan(stats.standard_deviation)); TS_ASSERT(std::isnan(stats.minimum)); TS_ASSERT(std::isnan(stats.maximum)); TS_ASSERT_EQUALS(stats.median, 17.2); } void test_Unsorted_Data_With_Sorted_Flag_Gives_Expected_Result_For_Median() { vector data; data.emplace_back(17.2); // Median value data.emplace_back(18.1); data.emplace_back(16.5); data.emplace_back(18.3); data.emplace_back(12.6); Statistics stats = getStatistics(data, (StatOptions::Median | StatOptions::SortedData)); TS_ASSERT(std::isnan(stats.mean)); TS_ASSERT(std::isnan(stats.standard_deviation)); TS_ASSERT(std::isnan(stats.minimum)); TS_ASSERT(std::isnan(stats.maximum)); TS_ASSERT_EQUALS(stats.median, 17.2); } void test_Doubles_With_Corrected_StdDev_Calculates_Mean() { vector data; data.emplace_back(17.2); data.emplace_back(18.1); data.emplace_back(16.5); data.emplace_back(18.3); data.emplace_back(12.6); sort(data.begin(), data.end()); Statistics stats = getStatistics(data, StatOptions::CorrectedStdDev); TS_ASSERT_EQUALS(stats.mean, 16.54); TS_ASSERT_DELTA(stats.standard_deviation, 2.3179, 0.0001); TS_ASSERT_EQUALS(stats.minimum, 12.6); TS_ASSERT_EQUALS(stats.maximum, 18.3); TS_ASSERT(std::isnan(stats.median)); } void test_Types_Can_Be_Disabled_With_Flags() { vector data; data.emplace_back(17.2); data.emplace_back(18.1); data.emplace_back(16.5); data.emplace_back(18.3); data.emplace_back(12.6); Statistics justMean = getStatistics(data, StatOptions::Mean); TS_ASSERT_EQUALS(justMean.mean, 16.54); TS_ASSERT(std::isnan(justMean.standard_deviation)); TS_ASSERT(std::isnan(justMean.minimum)); TS_ASSERT(std::isnan(justMean.maximum)); TS_ASSERT(std::isnan(justMean.median)); } void testZscores() { vector data; data.emplace_back(12); data.emplace_back(13); data.emplace_back(9); data.emplace_back(18); data.emplace_back(7); data.emplace_back(9); data.emplace_back(14); data.emplace_back(16); data.emplace_back(10); data.emplace_back(12); data.emplace_back(7); data.emplace_back(13); data.emplace_back(14); data.emplace_back(19); data.emplace_back(10); data.emplace_back(16); data.emplace_back(12); data.emplace_back(16); data.emplace_back(19); data.emplace_back(11); std::vector Zscore = getZscore(data); TS_ASSERT_DELTA(Zscore[4], 1.6397, 0.0001); TS_ASSERT_DELTA(Zscore[6], 0.3223, 0.0001); std::vector ZModscore = getModifiedZscore(data); TS_ASSERT_DELTA(ZModscore[4], 1.2365, 0.0001); TS_ASSERT_DELTA(ZModscore[6], 0.3372, 0.0001); } void testDoubleSingle() { vector data; data.emplace_back(42.); Statistics stats = getStatistics(data); TS_ASSERT_EQUALS(stats.mean, 42.); TS_ASSERT_EQUALS(stats.standard_deviation, 0.); TS_ASSERT_EQUALS(stats.minimum, 42.); TS_ASSERT_EQUALS(stats.maximum, 42.); TS_ASSERT_EQUALS(stats.median, 42.); } void testInt32Even() { vector data; data.emplace_back(1); data.emplace_back(2); data.emplace_back(3); data.emplace_back(4); data.emplace_back(5); data.emplace_back(6); Statistics stats = getStatistics(data); TS_ASSERT_EQUALS(stats.mean, 3.5); TS_ASSERT_DELTA(stats.standard_deviation, 1.7078, 0.0001); TS_ASSERT_EQUALS(stats.minimum, 1.); TS_ASSERT_EQUALS(stats.maximum, 6.); TS_ASSERT_EQUALS(stats.median, 3.5); } bool my_isnan(const double number) { return number != number; } void testString() { vector data{"hi there"}; Statistics stats = getStatistics(data); TS_ASSERT(my_isnan(stats.mean)); TS_ASSERT(my_isnan(stats.standard_deviation)); TS_ASSERT(my_isnan(stats.minimum)); TS_ASSERT(my_isnan(stats.maximum)); TS_ASSERT(my_isnan(stats.median)); } /** Test function to calculate Rwp */ void testRwp() { vector obsY(4); vector calY(4); vector obsE(4); obsY[0] = 1.0; calY[0] = 1.1; obsE[0] = 1.0; obsY[1] = 2.0; calY[1] = 2.1; obsE[1] = 1.2; obsY[2] = 3.0; calY[2] = 3.5; obsE[2] = 1.4; obsY[3] = 1.0; calY[3] = 1.3; obsE[3] = 1.0; Rfactor rfactor = getRFactor(obsY, calY, obsE); TS_ASSERT_DELTA(rfactor.Rwp, 0.1582, 0.0001); } /** Test throw exception */ void testRwpException1() { vector obsY{1.0, 2.0, 3.0, 1.0}; vector calY{1.1, 2.1, 3.5, 1.3}; vector obsE{1.0, 1.2, 1.4}; TS_ASSERT_THROWS_ANYTHING(getRFactor(obsY, calY, obsE)); } /** Test throw exception on empty array */ void testRwpException2() { vector obsY; vector calY; vector obsE; TS_ASSERT_THROWS_ANYTHING(getRFactor(obsY, calY, obsE)); } /// Test moment calculations about origin and mean void test_getMoments() { const double mean = 5.; const double sigma = 4.; const double deltaX = .2; const size_t numX = 200; // calculate to have same number of points left and right of function const double offsetX = mean - (.5 * deltaX * static_cast(numX)); // variance about origin double expVar = mean * mean + sigma * sigma; // skew about origin double expSkew = mean * mean * mean + 3. * mean * sigma * sigma; // x-values to try out vector x; for (size_t i = 0; i < numX; ++i) x.emplace_back(static_cast(i) * deltaX + offsetX); // just declare so we can have test of exception handling vector y; TS_ASSERT_THROWS(getMomentsAboutOrigin(x, y), const std::out_of_range &); // now calculate the y-values for (size_t i = 0; i < numX; ++i) { double temp = (x[i] - mean) / sigma; y.emplace_back(exp(-.5 * temp * temp) / (sigma * sqrt(2. * M_PI))); } // Normal distribution values are taken from the wikipedia page { std::cout << "Normal distribution about origin\n"; vector aboutOrigin = getMomentsAboutOrigin(x, y); TS_ASSERT_EQUALS(aboutOrigin.size(), 4); TS_ASSERT_DELTA(aboutOrigin[0], 1., .0001); TS_ASSERT_DELTA(aboutOrigin[1], mean, .0001); TS_ASSERT_DELTA(aboutOrigin[2], expVar, .001 * expVar); TS_ASSERT_DELTA(aboutOrigin[3], expSkew, .001 * expSkew); std::cout << "Normal distribution about mean\n"; vector aboutMean = getMomentsAboutMean(x, y); TS_ASSERT_EQUALS(aboutMean.size(), 4); TS_ASSERT_DELTA(aboutMean[0], 1., .0001); TS_ASSERT_DELTA(aboutMean[1], 0., .0001); TS_ASSERT_DELTA(aboutMean[2], sigma * sigma, .001 * expVar); TS_ASSERT_DELTA(aboutMean[3], 0., .0001 * expSkew); } // Now a gaussian function as a histogram y.clear(); for (size_t i = 0; i < numX - 1; ++i) // one less y than x makes it a histogram { double templeft = (x[i] - mean) / sigma; templeft = exp(-.5 * templeft * templeft) / (sigma * sqrt(2. * M_PI)); double tempright = (x[i + 1] - mean) / sigma; tempright = exp(-.5 * tempright * tempright) / (sigma * sqrt(2. * M_PI)); y.emplace_back(.5 * deltaX * (templeft + tempright)); // std::cout << i << ":\t" << x[i] << "\t" << y[i] << '\n'; } // Normal distribution values are taken from the wikipedia page { std::cout << "Normal distribution about origin\n"; vector aboutOrigin = getMomentsAboutOrigin(x, y); TS_ASSERT_EQUALS(aboutOrigin.size(), 4); TS_ASSERT_DELTA(aboutOrigin[0], 1., .0001); TS_ASSERT_DELTA(aboutOrigin[1], mean, .0001); TS_ASSERT_DELTA(aboutOrigin[2], expVar, .001 * expVar); TS_ASSERT_DELTA(aboutOrigin[3], expSkew, .001 * expSkew); std::cout << "Normal distribution about mean\n"; vector aboutMean = getMomentsAboutMean(x, y); TS_ASSERT_EQUALS(aboutMean.size(), 4); TS_ASSERT_DELTA(aboutMean[0], 1., .0001); TS_ASSERT_DELTA(aboutMean[1], 0., .0001); TS_ASSERT_DELTA(aboutMean[2], sigma * sigma, .001 * expVar); TS_ASSERT_DELTA(aboutMean[3], 0., .0001 * expSkew); } } };