StatisticsTest.h 9.58 KB
Newer Older
1
2
3
4
5
6
// 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
// SPDX - License - Identifier: GPL - 3.0 +
7
8
9
#ifndef STATISTICSTEST_H_
#define STATISTICSTEST_H_

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

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

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

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

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

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

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

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

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

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

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

  void test_Types_Can_Be_Disabled_With_Flags() {
    vector<double> data;
98
99
100
101
102
    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
103

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

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

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

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

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

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

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

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

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

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

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

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

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

  /** Test throw exception
LamarMoore's avatar
LamarMoore committed
217
   */
218
  void testRwpException1() {
219
220
221
    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};
222
223

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

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

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

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

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

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

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

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

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

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

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

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

307
      std::cout << "Normal distribution about mean\n";
308
309
310
311
      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);
312
313
      TS_ASSERT_DELTA(aboutMean[2], sigma * sigma, .001 * expVar);
      TS_ASSERT_DELTA(aboutMean[3], 0., .0001 * expSkew);
314
315
    }
  }
316
317
318
};

#endif // STATISTICSTEST_H_