StatisticsTest.h 9.55 KB
Newer Older
1
2
3
// Mantid Repository : https://github.com/mantidproject/mantid
//
// Copyright © 2018 ISIS Rutherford Appleton Laboratory UKRI,
4
5
//   NScD Oak Ridge National Laboratory, European Spallation Source,
//   Institut Laue - Langevin & CSNS, Institute of High Energy Physics, CAS
6
// SPDX - License - Identifier: GPL - 3.0 +
7
#pragma once
8

9
10
#include "MantidKernel/Statistics.h"
#include <algorithm>
11
#include <cmath>
LamarMoore's avatar
LamarMoore committed
12
#include <cxxtest/TestSuite.h>
13
#include <string>
LamarMoore's avatar
LamarMoore committed
14
#include <vector>
15
16
17
18
19

using namespace Mantid::Kernel;
using std::string;
using std::vector;

20
class StatisticsTest : public CxxTest::TestSuite {
21
public:
22
  void test_Doubles_And_Default_Flags_Calculates_All_Stats() {
23
    vector<double> data;
24
25
26
27
28
    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);
29
30
31
32
33
34
35
36

    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);
37
38
  }

39
  void test_Doubles_With_Sorted_Data() {
40
    vector<double> data;
41
42
43
44
45
    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);
46
47
    sort(data.begin(), data.end());

48
49
    Statistics stats =
        getStatistics(data, (StatOptions::Median | StatOptions::SortedData));
50

51
52
53
54
    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));
55
56
57
    TS_ASSERT_EQUALS(stats.median, 17.2);
  }

58
59
  void
  test_Unsorted_Data_With_Sorted_Flag_Gives_Expected_Incorrect_Result_For_Median() {
60
    vector<double> data;
61
62
63
64
65
    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);
66

67
68
    Statistics stats =
        getStatistics(data, (StatOptions::Median | StatOptions::SortedData));
69

70
71
72
73
    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));
74
75
    TS_ASSERT_EQUALS(stats.median, 16.5);
  }
76
77

  void test_Doubles_With_Corrected_StdDev_Calculates_Mean() {
78
    vector<double> data;
79
80
81
82
83
    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);
84
85
86
87
88
89
90
91
    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);
92
    TS_ASSERT(std::isnan(stats.median));
93
94
95
96
  }

  void test_Types_Can_Be_Disabled_With_Flags() {
    vector<double> data;
97
98
99
100
101
    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);
Lynch, Vickie's avatar
Lynch, Vickie committed
102

103
104
    Statistics justMean = getStatistics(data, StatOptions::Mean);
    TS_ASSERT_EQUALS(justMean.mean, 16.54);
105
106
107
108
    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));
Lynch, Vickie's avatar
Lynch, Vickie committed
109
  }
110
111

  void testZscores() {
Lynch, Vickie's avatar
Lynch, Vickie committed
112
    vector<double> data;
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
    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);
Lynch, Vickie's avatar
Lynch, Vickie committed
133
134
135
136
137
138
139

    std::vector<double> Zscore = getZscore(data);
    TS_ASSERT_DELTA(Zscore[4], 1.6397, 0.0001);
    TS_ASSERT_DELTA(Zscore[6], 0.3223, 0.0001);
    std::vector<double> ZModscore = getModifiedZscore(data);
    TS_ASSERT_DELTA(ZModscore[4], 1.2365, 0.0001);
    TS_ASSERT_DELTA(ZModscore[6], 0.3372, 0.0001);
140
141
  }

142
  void testDoubleSingle() {
143
    vector<double> data;
144
    data.emplace_back(42.);
145
146
147
148
149
150
151
152
153
154

    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.);
  }

155
  void testInt32Even() {
156
    vector<int32_t> data;
157
158
159
160
161
162
    data.emplace_back(1);
    data.emplace_back(2);
    data.emplace_back(3);
    data.emplace_back(4);
    data.emplace_back(5);
    data.emplace_back(6);
163
164
165
166
167
168
169
170
171
172

    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);
  }

173
  bool my_isnan(const double number) { return number != number; }
174

175
  void testString() {
176
    vector<string> data{"hi there"};
177
178
179
180
181
182
183
184
185

    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));
  }
186
187

  /** Test function to calculate Rwp
LamarMoore's avatar
LamarMoore committed
188
   */
189
  void testRwp() {
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
    vector<double> obsY(4);
    vector<double> calY(4);
    vector<double> 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;

210
    Rfactor rfactor = getRFactor(obsY, calY, obsE);
211

212
    TS_ASSERT_DELTA(rfactor.Rwp, 0.1582, 0.0001);
213
214
215
  }

  /** Test throw exception
LamarMoore's avatar
LamarMoore committed
216
   */
217
  void testRwpException1() {
218
219
220
    vector<double> obsY{1.0, 2.0, 3.0, 1.0};
    vector<double> calY{1.1, 2.1, 3.5, 1.3};
    vector<double> obsE{1.0, 1.2, 1.4};
221
222

    TS_ASSERT_THROWS_ANYTHING(getRFactor(obsY, calY, obsE));
223
  }
224
225

  /** Test throw exception on empty array
LamarMoore's avatar
LamarMoore committed
226
   */
227
  void testRwpException2() {
228
229
230
231
232
233
234
    vector<double> obsY;
    vector<double> calY;
    vector<double> obsE;

    TS_ASSERT_THROWS_ANYTHING(getRFactor(obsY, calY, obsE));
  }

235
  /// Test moment calculations about origin and mean
236
  void test_getMoments() {
237
238
239
240
241
242
243
    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<double>(numX));
    // variance about origin
244
    double expVar = mean * mean + sigma * sigma;
245
    // skew about origin
246
    double expSkew = mean * mean * mean + 3. * mean * sigma * sigma;
247
248
249
250

    // x-values to try out
    vector<double> x;
    for (size_t i = 0; i < numX; ++i)
251
      x.emplace_back(static_cast<double>(i) * deltaX + offsetX);
252
253
254
255

    // just declare so we can have test of exception handling
    vector<double> y;

256
    TS_ASSERT_THROWS(getMomentsAboutOrigin(x, y), const std::out_of_range &);
257
258

    // now calculate the y-values
259
260
    for (size_t i = 0; i < numX; ++i) {
      double temp = (x[i] - mean) / sigma;
261
      y.emplace_back(exp(-.5 * temp * temp) / (sigma * sqrt(2. * M_PI)));
262
263
264
265
    }

    // Normal distribution values are taken from the wikipedia page
    {
266
      std::cout << "Normal distribution about origin\n";
267
268
269
270
      vector<double> aboutOrigin = getMomentsAboutOrigin(x, y);
      TS_ASSERT_EQUALS(aboutOrigin.size(), 4);
      TS_ASSERT_DELTA(aboutOrigin[0], 1., .0001);
      TS_ASSERT_DELTA(aboutOrigin[1], mean, .0001);
271
272
      TS_ASSERT_DELTA(aboutOrigin[2], expVar, .001 * expVar);
      TS_ASSERT_DELTA(aboutOrigin[3], expSkew, .001 * expSkew);
273

274
      std::cout << "Normal distribution about mean\n";
275
276
277
278
      vector<double> aboutMean = getMomentsAboutMean(x, y);
      TS_ASSERT_EQUALS(aboutMean.size(), 4);
      TS_ASSERT_DELTA(aboutMean[0], 1., .0001);
      TS_ASSERT_DELTA(aboutMean[1], 0., .0001);
279
280
      TS_ASSERT_DELTA(aboutMean[2], sigma * sigma, .001 * expVar);
      TS_ASSERT_DELTA(aboutMean[3], 0., .0001 * expSkew);
281
282
283
284
    }

    // Now a gaussian function as a histogram
    y.clear();
285
286
    for (size_t i = 0; i < numX - 1;
         ++i) // one less y than x makes it a histogram
287
    {
288
289
290
291
      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));
292
      y.emplace_back(.5 * deltaX * (templeft + tempright));
293
      //      std::cout << i << ":\t" << x[i] << "\t" << y[i] << '\n';
294
295
296
297
    }

    // Normal distribution values are taken from the wikipedia page
    {
298
      std::cout << "Normal distribution about origin\n";
299
300
301
302
      vector<double> aboutOrigin = getMomentsAboutOrigin(x, y);
      TS_ASSERT_EQUALS(aboutOrigin.size(), 4);
      TS_ASSERT_DELTA(aboutOrigin[0], 1., .0001);
      TS_ASSERT_DELTA(aboutOrigin[1], mean, .0001);
303
304
      TS_ASSERT_DELTA(aboutOrigin[2], expVar, .001 * expVar);
      TS_ASSERT_DELTA(aboutOrigin[3], expSkew, .001 * expSkew);
305

306
      std::cout << "Normal distribution about mean\n";
307
308
309
310
      vector<double> aboutMean = getMomentsAboutMean(x, y);
      TS_ASSERT_EQUALS(aboutMean.size(), 4);
      TS_ASSERT_DELTA(aboutMean[0], 1., .0001);
      TS_ASSERT_DELTA(aboutMean[1], 0., .0001);
311
312
      TS_ASSERT_DELTA(aboutMean[2], sigma * sigma, .001 * expVar);
      TS_ASSERT_DELTA(aboutMean[3], 0., .0001 * expSkew);
313
314
    }
  }
315
};