StatisticsTest.h 9.53 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());

Samuel Jones's avatar
Samuel Jones committed
48
    Statistics stats = getStatistics(data, (StatOptions::Median | StatOptions::SortedData));
49

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

Samuel Jones's avatar
Samuel Jones committed
57
  void test_Unsorted_Data_With_Sorted_Flag_Gives_Expected_Incorrect_Result_For_Median() {
58
    vector<double> data;
59
60
61
62
63
    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);
64

Samuel Jones's avatar
Samuel Jones committed
65
    Statistics stats = getStatistics(data, (StatOptions::Median | StatOptions::SortedData));
66

67
68
69
70
    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));
71
72
    TS_ASSERT_EQUALS(stats.median, 16.5);
  }
73
74

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

  void test_Types_Can_Be_Disabled_With_Flags() {
    vector<double> data;
94
95
96
97
98
    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
99

100
101
    Statistics justMean = getStatistics(data, StatOptions::Mean);
    TS_ASSERT_EQUALS(justMean.mean, 16.54);
102
103
104
105
    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
106
  }
107
108

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

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

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

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

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

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

170
  bool my_isnan(const double number) { return number != number; }
171

172
  void testString() {
173
    vector<string> data{"hi there"};
174
175
176
177
178
179
180
181
182

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

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

207
    Rfactor rfactor = getRFactor(obsY, calY, obsE);
208

209
    TS_ASSERT_DELTA(rfactor.Rwp, 0.1582, 0.0001);
210
211
212
  }

  /** Test throw exception
LamarMoore's avatar
LamarMoore committed
213
   */
214
  void testRwpException1() {
215
216
217
    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};
218
219

    TS_ASSERT_THROWS_ANYTHING(getRFactor(obsY, calY, obsE));
220
  }
221
222

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

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

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

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

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

253
    TS_ASSERT_THROWS(getMomentsAboutOrigin(x, y), const std::out_of_range &);
254
255

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

    // Normal distribution values are taken from the wikipedia page
    {
263
      std::cout << "Normal distribution about origin\n";
264
265
266
267
      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);
268
269
      TS_ASSERT_DELTA(aboutOrigin[2], expVar, .001 * expVar);
      TS_ASSERT_DELTA(aboutOrigin[3], expSkew, .001 * expSkew);
270

271
      std::cout << "Normal distribution about mean\n";
272
273
274
275
      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);
276
277
      TS_ASSERT_DELTA(aboutMean[2], sigma * sigma, .001 * expVar);
      TS_ASSERT_DELTA(aboutMean[3], 0., .0001 * expSkew);
278
279
280
281
    }

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

    // Normal distribution values are taken from the wikipedia page
    {
294
      std::cout << "Normal distribution about origin\n";
295
296
297
298
      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);
299
300
      TS_ASSERT_DELTA(aboutOrigin[2], expVar, .001 * expVar);
      TS_ASSERT_DELTA(aboutOrigin[3], expSkew, .001 * expSkew);
301

302
      std::cout << "Normal distribution about mean\n";
303
304
305
306
      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);
307
308
      TS_ASSERT_DELTA(aboutMean[2], sigma * sigma, .001 * expVar);
      TS_ASSERT_DELTA(aboutMean[3], 0., .0001 * expSkew);
309
310
    }
  }
311
};