Imported Upstream version 1.72.0
[platform/upstream/boost.git] / libs / math / test / univariate_statistics_test.cpp
1 /*
2  *  (C) Copyright Nick Thompson 2018.
3  *  Use, modification and distribution are subject to the
4  *  Boost Software License, Version 1.0. (See accompanying file
5  *  LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
6  */
7
8 #include <vector>
9 #include <array>
10 #include <forward_list>
11 #include <algorithm>
12 #include <random>
13 #include <boost/core/lightweight_test.hpp>
14 #include <boost/numeric/ublas/vector.hpp>
15 #include <boost/math/constants/constants.hpp>
16 #include <boost/math/statistics/univariate_statistics.hpp>
17 #include <boost/multiprecision/cpp_bin_float.hpp>
18 #include <boost/multiprecision/cpp_complex.hpp>
19
20 using boost::multiprecision::cpp_bin_float_50;
21 using boost::multiprecision::cpp_complex_50;
22
23 /*
24  * Test checklist:
25  * 1) Does it work with multiprecision?
26  * 2) Does it work with .cbegin()/.cend() if the data is not altered?
27  * 3) Does it work with ublas and std::array? (Checking Eigen and Armadillo will make the CI system really unhappy.)
28  * 4) Does it work with std::forward_list if a forward iterator is all that is required?
29  * 5) Does it work with complex data if complex data is sensible?
30  */
31
32  // To stress test, set global_seed = 0, global_size = huge.
33  static const constexpr size_t global_seed = 0;
34  static const constexpr size_t global_size = 128;
35
36 template<class T>
37 std::vector<T> generate_random_vector(size_t size, size_t seed)
38 {
39     if (seed == 0)
40     {
41         std::random_device rd;
42         seed = rd();
43     }
44     std::vector<T> v(size);
45
46     std::mt19937 gen(seed);
47
48     if constexpr (std::is_floating_point<T>::value)
49     {
50         std::normal_distribution<T> dis(0, 1);
51         for (size_t i = 0; i < v.size(); ++i)
52         {
53          v[i] = dis(gen);
54         }
55         return v;
56     }
57     else if constexpr (std::is_integral<T>::value)
58     {
59         // Rescaling by larger than 2 is UB!
60         std::uniform_int_distribution<T> dis(std::numeric_limits<T>::lowest()/2, (std::numeric_limits<T>::max)()/2);
61         for (size_t i = 0; i < v.size(); ++i)
62         {
63          v[i] = dis(gen);
64         }
65         return v;
66     }
67     else if constexpr (boost::is_complex<T>::value)
68     {
69         std::normal_distribution<typename T::value_type> dis(0, 1);
70         for (size_t i = 0; i < v.size(); ++i)
71         {
72             v[i] = {dis(gen), dis(gen)};
73         }
74         return v;
75     }
76     else if constexpr (boost::multiprecision::number_category<T>::value == boost::multiprecision::number_kind_complex)
77     {
78         std::normal_distribution<long double> dis(0, 1);
79         for (size_t i = 0; i < v.size(); ++i)
80         {
81             v[i] = {dis(gen), dis(gen)};
82         }
83         return v;
84     }
85     else if constexpr (boost::multiprecision::number_category<T>::value == boost::multiprecision::number_kind_floating_point)
86     {
87         std::normal_distribution<long double> dis(0, 1);
88         for (size_t i = 0; i < v.size(); ++i)
89         {
90             v[i] = dis(gen);
91         }
92         return v;
93     }
94     else
95     {
96         BOOST_ASSERT_MSG(false, "Could not identify type for random vector generation.");
97         return v;
98     }
99 }
100
101
102 template<class Z>
103 void test_integer_mean()
104 {
105     double tol = 100*std::numeric_limits<double>::epsilon();
106     std::vector<Z> v{1,2,3,4,5};
107     double mu = boost::math::statistics::mean(v);
108     BOOST_TEST(abs(mu - 3) < tol);
109
110     // Work with std::array?
111     std::array<Z, 5> w{1,2,3,4,5};
112     mu = boost::math::statistics::mean(w);
113     BOOST_TEST(abs(mu - 3) < tol);
114
115     v = generate_random_vector<Z>(global_size, global_seed);
116     Z scale = 2;
117
118     double m1 = scale*boost::math::statistics::mean(v);
119     for (auto & x : v)
120     {
121         x *= scale;
122     }
123     double m2 = boost::math::statistics::mean(v);
124     BOOST_TEST(abs(m1 - m2) < tol*abs(m1));
125 }
126
127 template<class RandomAccessContainer>
128 auto naive_mean(RandomAccessContainer const & v)
129 {
130     typename RandomAccessContainer::value_type sum = 0;
131     for (auto & x : v)
132     {
133         sum += x;
134     }
135     return sum/v.size();
136 }
137
138 template<class Real>
139 void test_mean()
140 {
141     Real tol = std::numeric_limits<Real>::epsilon();
142     std::vector<Real> v{1,2,3,4,5};
143     Real mu = boost::math::statistics::mean(v.begin(), v.end());
144     BOOST_TEST(abs(mu - 3) < tol);
145
146     // Does range call work?
147     mu = boost::math::statistics::mean(v);
148     BOOST_TEST(abs(mu - 3) < tol);
149
150     // Can we successfully average only part of the vector?
151     mu = boost::math::statistics::mean(v.begin(), v.begin() + 3);
152     BOOST_TEST(abs(mu - 2) < tol);
153
154     // Does it work when we const qualify?
155     mu = boost::math::statistics::mean(v.cbegin(), v.cend());
156     BOOST_TEST(abs(mu - 3) < tol);
157
158     // Does it work for std::array?
159     std::array<Real, 7> u{1,2,3,4,5,6,7};
160     mu = boost::math::statistics::mean(u.begin(), u.end());
161     BOOST_TEST(abs(mu - 4) < tol);
162
163     // Does it work for a forward iterator?
164     std::forward_list<Real> l{1,2,3,4,5,6,7};
165     mu = boost::math::statistics::mean(l.begin(), l.end());
166     BOOST_TEST(abs(mu - 4) < tol);
167
168     // Does it work with ublas vectors?
169     boost::numeric::ublas::vector<Real> w(7);
170     for (size_t i = 0; i < w.size(); ++i)
171     {
172         w[i] = i+1;
173     }
174     mu = boost::math::statistics::mean(w.cbegin(), w.cend());
175     BOOST_TEST(abs(mu - 4) < tol);
176
177     v = generate_random_vector<Real>(global_size, global_seed);
178     Real scale = 2;
179     Real m1 = scale*boost::math::statistics::mean(v);
180     for (auto & x : v)
181     {
182         x *= scale;
183     }
184     Real m2 = boost::math::statistics::mean(v);
185     BOOST_TEST(abs(m1 - m2) < tol*abs(m1));
186
187     // Stress test:
188     for (size_t i = 1; i < 30; ++i)
189     {
190         v = generate_random_vector<Real>(i, 12803);
191         auto naive_ = naive_mean(v);
192         auto higham_ = boost::math::statistics::mean(v);
193         if (abs(higham_ - naive_) >= 100*tol*abs(naive_))
194         {
195             std::cout << std::hexfloat;
196             std::cout << "Terms = " << v.size() << "\n";
197             std::cout << "higham = " << higham_ << "\n";
198             std::cout << "naive_ = " << naive_ << "\n";
199         }
200         BOOST_TEST(abs(higham_ - naive_) < 100*tol*abs(naive_));
201     }
202
203 }
204
205 template<class Complex>
206 void test_complex_mean()
207 {
208     typedef typename Complex::value_type Real;
209     Real tol = std::numeric_limits<Real>::epsilon();
210     std::vector<Complex> v{{0,1},{0,2},{0,3},{0,4},{0,5}};
211     auto mu = boost::math::statistics::mean(v.begin(), v.end());
212     BOOST_TEST(abs(mu.imag() - 3) < tol);
213     BOOST_TEST(abs(mu.real()) < tol);
214
215     // Does range work?
216     mu = boost::math::statistics::mean(v);
217     BOOST_TEST(abs(mu.imag() - 3) < tol);
218     BOOST_TEST(abs(mu.real()) < tol);
219 }
220
221 template<class Real>
222 void test_variance()
223 {
224     Real tol = std::numeric_limits<Real>::epsilon();
225     std::vector<Real> v{1,1,1,1,1,1};
226     Real sigma_sq = boost::math::statistics::variance(v.begin(), v.end());
227     BOOST_TEST(abs(sigma_sq) < tol);
228
229     sigma_sq = boost::math::statistics::variance(v);
230     BOOST_TEST(abs(sigma_sq) < tol);
231
232     Real s_sq = boost::math::statistics::sample_variance(v);
233     BOOST_TEST(abs(s_sq) < tol);
234
235     std::vector<Real> u{1};
236     sigma_sq = boost::math::statistics::variance(u.cbegin(), u.cend());
237     BOOST_TEST(abs(sigma_sq) < tol);
238
239     std::array<Real, 8> w{0,1,0,1,0,1,0,1};
240     sigma_sq = boost::math::statistics::variance(w.begin(), w.end());
241     BOOST_TEST(abs(sigma_sq - 1.0/4.0) < tol);
242
243     sigma_sq = boost::math::statistics::variance(w);
244     BOOST_TEST(abs(sigma_sq - 1.0/4.0) < tol);
245
246     std::forward_list<Real> l{0,1,0,1,0,1,0,1};
247     sigma_sq = boost::math::statistics::variance(l.begin(), l.end());
248     BOOST_TEST(abs(sigma_sq - 1.0/4.0) < tol);
249
250     v = generate_random_vector<Real>(global_size, global_seed);
251     Real scale = 2;
252     Real m1 = scale*scale*boost::math::statistics::variance(v);
253     for (auto & x : v)
254     {
255         x *= scale;
256     }
257     Real m2 = boost::math::statistics::variance(v);
258     BOOST_TEST(abs(m1 - m2) < tol*abs(m1));
259
260     // Wikipedia example for a variance of N sided die:
261     // https://en.wikipedia.org/wiki/Variance
262     for (size_t j = 16; j < 2048; j *= 2)
263     {
264         v.resize(1024);
265         Real n = v.size();
266         for (size_t i = 0; i < v.size(); ++i)
267         {
268             v[i] = i + 1;
269         }
270
271         sigma_sq = boost::math::statistics::variance(v);
272
273         BOOST_TEST(abs(sigma_sq - (n*n-1)/Real(12)) <= tol*sigma_sq);
274     }
275
276 }
277
278 template<class Z>
279 void test_integer_variance()
280 {
281     double tol = std::numeric_limits<double>::epsilon();
282     std::vector<Z> v{1,1,1,1,1,1};
283     double sigma_sq = boost::math::statistics::variance(v);
284     BOOST_TEST(abs(sigma_sq) < tol);
285
286     std::forward_list<Z> l{0,1,0,1,0,1,0,1};
287     sigma_sq = boost::math::statistics::variance(l.begin(), l.end());
288     BOOST_TEST(abs(sigma_sq - 1.0/4.0) < tol);
289
290     v = generate_random_vector<Z>(global_size, global_seed);
291     Z scale = 2;
292     double m1 = scale*scale*boost::math::statistics::variance(v);
293     for (auto & x : v)
294     {
295         x *= scale;
296     }
297     double m2 = boost::math::statistics::variance(v);
298     BOOST_TEST(abs(m1 - m2) < tol*abs(m1));
299 }
300
301 template<class Z>
302 void test_integer_skewness()
303 {
304     double tol = std::numeric_limits<double>::epsilon();
305     std::vector<Z> v{1,1,1};
306     double skew = boost::math::statistics::skewness(v);
307     BOOST_TEST(abs(skew) < tol);
308
309     // Dataset is symmetric about the mean:
310     v = {1,2,3,4,5};
311     skew = boost::math::statistics::skewness(v);
312     BOOST_TEST(abs(skew) < tol);
313
314     v = {0,0,0,0,5};
315     // mu = 1, sigma^2 = 4, sigma = 2, skew = 3/2
316     skew = boost::math::statistics::skewness(v);
317     BOOST_TEST(abs(skew - 3.0/2.0) < tol);
318
319     std::forward_list<Z> v2{0,0,0,0,5};
320     skew = boost::math::statistics::skewness(v);
321     BOOST_TEST(abs(skew - 3.0/2.0) < tol);
322
323
324     v = generate_random_vector<Z>(global_size, global_seed);
325     Z scale = 2;
326     double m1 = boost::math::statistics::skewness(v);
327     for (auto & x : v)
328     {
329         x *= scale;
330     }
331     double m2 = boost::math::statistics::skewness(v);
332     BOOST_TEST(abs(m1 - m2) < tol*abs(m1));
333
334 }
335
336 template<class Real>
337 void test_skewness()
338 {
339     Real tol = std::numeric_limits<Real>::epsilon();
340     std::vector<Real> v{1,1,1};
341     Real skew = boost::math::statistics::skewness(v);
342     BOOST_TEST(abs(skew) < tol);
343
344     // Dataset is symmetric about the mean:
345     v = {1,2,3,4,5};
346     skew = boost::math::statistics::skewness(v);
347     BOOST_TEST(abs(skew) < tol);
348
349     v = {0,0,0,0,5};
350     // mu = 1, sigma^2 = 4, sigma = 2, skew = 3/2
351     skew = boost::math::statistics::skewness(v);
352     BOOST_TEST(abs(skew - Real(3)/Real(2)) < tol);
353
354     std::array<Real, 5> w1{0,0,0,0,5};
355     skew = boost::math::statistics::skewness(w1);
356     BOOST_TEST(abs(skew - Real(3)/Real(2)) < tol);
357
358     std::forward_list<Real> w2{0,0,0,0,5};
359     skew = boost::math::statistics::skewness(w2);
360     BOOST_TEST(abs(skew - Real(3)/Real(2)) < tol);
361
362     v = generate_random_vector<Real>(global_size, global_seed);
363     Real scale = 2;
364     Real m1 = boost::math::statistics::skewness(v);
365     for (auto & x : v)
366     {
367         x *= scale;
368     }
369     Real m2 = boost::math::statistics::skewness(v);
370     BOOST_TEST(abs(m1 - m2) < tol*abs(m1));
371 }
372
373 template<class Real>
374 void test_kurtosis()
375 {
376     Real tol = std::numeric_limits<Real>::epsilon();
377     std::vector<Real> v{1,1,1};
378     Real kurt = boost::math::statistics::kurtosis(v);
379     BOOST_TEST(abs(kurt) < tol);
380
381     v = {1,2,3,4,5};
382     // mu =1, sigma^2 = 2, kurtosis = 17/10
383     kurt = boost::math::statistics::kurtosis(v);
384     BOOST_TEST(abs(kurt - Real(17)/Real(10)) < tol);
385
386     v = {0,0,0,0,5};
387     // mu = 1, sigma^2 = 4, sigma = 2, skew = 3/2, kurtosis = 13/4
388     kurt = boost::math::statistics::kurtosis(v);
389     BOOST_TEST(abs(kurt - Real(13)/Real(4)) < tol);
390
391     std::array<Real, 5> v1{0,0,0,0,5};
392     kurt = boost::math::statistics::kurtosis(v1);
393     BOOST_TEST(abs(kurt - Real(13)/Real(4)) < tol);
394
395     std::forward_list<Real> v2{0,0,0,0,5};
396     kurt = boost::math::statistics::kurtosis(v2);
397     BOOST_TEST(abs(kurt - Real(13)/Real(4)) < tol);
398
399     std::vector<Real> v3(10000);
400     std::mt19937 gen(42);
401     std::normal_distribution<long double> dis(0, 1);
402     for (size_t i = 0; i < v3.size(); ++i) {
403         v3[i] = dis(gen);
404     }
405     kurt = boost::math::statistics::kurtosis(v3);
406     BOOST_TEST(abs(kurt - 3) < 0.1);
407
408     std::uniform_real_distribution<long double> udis(-1, 3);
409     for (size_t i = 0; i < v3.size(); ++i) {
410         v3[i] = udis(gen);
411     }
412     auto excess_kurtosis = boost::math::statistics::excess_kurtosis(v3);
413     BOOST_TEST(abs(excess_kurtosis + 6.0/5.0) < 0.2);
414
415     v = generate_random_vector<Real>(global_size, global_seed);
416     Real scale = 2;
417     Real m1 = boost::math::statistics::kurtosis(v);
418     for (auto & x : v)
419     {
420         x *= scale;
421     }
422     Real m2 = boost::math::statistics::kurtosis(v);
423     BOOST_TEST(abs(m1 - m2) < tol*abs(m1));
424
425     // This test only passes when there are a large number of samples.
426     // Otherwise, the distribution doesn't generate enough outliers to give,
427     // or generates too many, giving pretty wildly different values of kurtosis on different runs.
428     // However, by kicking up the samples to 1,000,000, I got very close to 6 for the excess kurtosis on every run.
429     // The CI system, however, would die on a million long doubles.
430     //v3.resize(1000000);
431     //std::exponential_distribution<long double> edis(0.1);
432     //for (size_t i = 0; i < v3.size(); ++i) {
433     //    v3[i] = edis(gen);
434     //}
435     //excess_kurtosis = boost::math::statistics::kurtosis(v3) - 3;
436     //BOOST_TEST(abs(excess_kurtosis - 6.0) < 0.2);
437 }
438
439 template<class Z>
440 void test_integer_kurtosis()
441 {
442     double tol = std::numeric_limits<double>::epsilon();
443     std::vector<Z> v{1,1,1};
444     double kurt = boost::math::statistics::kurtosis(v);
445     BOOST_TEST(abs(kurt) < tol);
446
447     v = {1,2,3,4,5};
448     // mu =1, sigma^2 = 2, kurtosis = 17/10
449     kurt = boost::math::statistics::kurtosis(v);
450     BOOST_TEST(abs(kurt - 17.0/10.0) < tol);
451
452     v = {0,0,0,0,5};
453     // mu = 1, sigma^2 = 4, sigma = 2, skew = 3/2, kurtosis = 13/4
454     kurt = boost::math::statistics::kurtosis(v);
455     BOOST_TEST(abs(kurt - 13.0/4.0) < tol);
456
457     v = generate_random_vector<Z>(global_size, global_seed);
458     Z scale = 2;
459     double m1 = boost::math::statistics::kurtosis(v);
460     for (auto & x : v)
461     {
462         x *= scale;
463     }
464     double m2 = boost::math::statistics::kurtosis(v);
465     BOOST_TEST(abs(m1 - m2) < tol*abs(m1));
466 }
467
468 template<class Real>
469 void test_first_four_moments()
470 {
471     Real tol = 10*std::numeric_limits<Real>::epsilon();
472     std::vector<Real> v{1,1,1};
473     auto [M1_1, M2_1, M3_1, M4_1] = boost::math::statistics::first_four_moments(v);
474     BOOST_TEST(abs(M1_1 - 1) < tol);
475     BOOST_TEST(abs(M2_1) < tol);
476     BOOST_TEST(abs(M3_1) < tol);
477     BOOST_TEST(abs(M4_1) < tol);
478
479     v = {1, 2, 3, 4, 5};
480     auto [M1_2, M2_2, M3_2, M4_2] = boost::math::statistics::first_four_moments(v);
481     BOOST_TEST(abs(M1_2 - 3) < tol);
482     BOOST_TEST(abs(M2_2 - 2) < tol);
483     BOOST_TEST(abs(M3_2) < tol);
484     BOOST_TEST(abs(M4_2 - Real(34)/Real(5)) < tol);
485 }
486
487 template<class Real>
488 void test_median()
489 {
490     std::mt19937 g(12);
491     std::vector<Real> v{1,2,3,4,5,6,7};
492
493     Real m = boost::math::statistics::median(v.begin(), v.end());
494     BOOST_TEST_EQ(m, 4);
495
496     std::shuffle(v.begin(), v.end(), g);
497     // Does range call work?
498     m = boost::math::statistics::median(v);
499     BOOST_TEST_EQ(m, 4);
500
501     v = {1,2,3,3,4,5};
502     m = boost::math::statistics::median(v.begin(), v.end());
503     BOOST_TEST_EQ(m, 3);
504     std::shuffle(v.begin(), v.end(), g);
505     m = boost::math::statistics::median(v.begin(), v.end());
506     BOOST_TEST_EQ(m, 3);
507
508     v = {1};
509     m = boost::math::statistics::median(v.begin(), v.end());
510     BOOST_TEST_EQ(m, 1);
511
512     v = {1,1};
513     m = boost::math::statistics::median(v.begin(), v.end());
514     BOOST_TEST_EQ(m, 1);
515
516     v = {2,4};
517     m = boost::math::statistics::median(v.begin(), v.end());
518     BOOST_TEST_EQ(m, 3);
519
520     v = {1,1,1};
521     m = boost::math::statistics::median(v.begin(), v.end());
522     BOOST_TEST_EQ(m, 1);
523
524     v = {1,2,3};
525     m = boost::math::statistics::median(v.begin(), v.end());
526     BOOST_TEST_EQ(m, 2);
527     std::shuffle(v.begin(), v.end(), g);
528     m = boost::math::statistics::median(v.begin(), v.end());
529     BOOST_TEST_EQ(m, 2);
530
531     // Does it work with std::array?
532     std::array<Real, 3> w{1,2,3};
533     m = boost::math::statistics::median(w);
534     BOOST_TEST_EQ(m, 2);
535
536     // Does it work with ublas?
537     boost::numeric::ublas::vector<Real> w1(3);
538     w1[0] = 1;
539     w1[1] = 2;
540     w1[2] = 3;
541     m = boost::math::statistics::median(w);
542     BOOST_TEST_EQ(m, 2);
543 }
544
545 template<class Real>
546 void test_median_absolute_deviation()
547 {
548     std::vector<Real> v{-1, 2, -3, 4, -5, 6, -7};
549
550     Real m = boost::math::statistics::median_absolute_deviation(v.begin(), v.end(), 0);
551     BOOST_TEST_EQ(m, 4);
552
553     std::mt19937 g(12);
554     std::shuffle(v.begin(), v.end(), g);
555     m = boost::math::statistics::median_absolute_deviation(v, 0);
556     BOOST_TEST_EQ(m, 4);
557
558     v = {1, -2, -3, 3, -4, -5};
559     m = boost::math::statistics::median_absolute_deviation(v.begin(), v.end(), 0);
560     BOOST_TEST_EQ(m, 3);
561     std::shuffle(v.begin(), v.end(), g);
562     m = boost::math::statistics::median_absolute_deviation(v.begin(), v.end(), 0);
563     BOOST_TEST_EQ(m, 3);
564
565     v = {-1};
566     m = boost::math::statistics::median_absolute_deviation(v.begin(), v.end(), 0);
567     BOOST_TEST_EQ(m, 1);
568
569     v = {-1, 1};
570     m = boost::math::statistics::median_absolute_deviation(v.begin(), v.end(), 0);
571     BOOST_TEST_EQ(m, 1);
572     // The median is zero, so coincides with the default:
573     m = boost::math::statistics::median_absolute_deviation(v.begin(), v.end());
574     BOOST_TEST_EQ(m, 1);
575
576     m = boost::math::statistics::median_absolute_deviation(v);
577     BOOST_TEST_EQ(m, 1);
578
579
580     v = {2, -4};
581     m = boost::math::statistics::median_absolute_deviation(v.begin(), v.end(), 0);
582     BOOST_TEST_EQ(m, 3);
583
584     v = {1, -1, 1};
585     m = boost::math::statistics::median_absolute_deviation(v.begin(), v.end(), 0);
586     BOOST_TEST_EQ(m, 1);
587
588     v = {1, 2, -3};
589     m = boost::math::statistics::median_absolute_deviation(v.begin(), v.end(), 0);
590     BOOST_TEST_EQ(m, 2);
591     std::shuffle(v.begin(), v.end(), g);
592     m = boost::math::statistics::median_absolute_deviation(v.begin(), v.end(), 0);
593     BOOST_TEST_EQ(m, 2);
594
595     std::array<Real, 3> w{1, 2, -3};
596     m = boost::math::statistics::median_absolute_deviation(w, 0);
597     BOOST_TEST_EQ(m, 2);
598
599     // boost.ublas vector?
600     boost::numeric::ublas::vector<Real> u(6);
601     u[0] = 1;
602     u[1] = 2;
603     u[2] = -3;
604     u[3] = 1;
605     u[4] = 2;
606     u[5] = -3;
607     m = boost::math::statistics::median_absolute_deviation(u, 0);
608     BOOST_TEST_EQ(m, 2);
609 }
610
611
612 template<class Real>
613 void test_sample_gini_coefficient()
614 {
615     Real tol = std::numeric_limits<Real>::epsilon();
616     std::vector<Real> v{1,0,0};
617     Real gini = boost::math::statistics::sample_gini_coefficient(v.begin(), v.end());
618     BOOST_TEST(abs(gini - 1) < tol);
619
620     gini = boost::math::statistics::sample_gini_coefficient(v);
621     BOOST_TEST(abs(gini - 1) < tol);
622
623     v[0] = 1;
624     v[1] = 1;
625     v[2] = 1;
626     gini = boost::math::statistics::sample_gini_coefficient(v.begin(), v.end());
627     BOOST_TEST(abs(gini) < tol);
628
629     v[0] = 0;
630     v[1] = 0;
631     v[2] = 0;
632     gini = boost::math::statistics::sample_gini_coefficient(v.begin(), v.end());
633     BOOST_TEST(abs(gini) < tol);
634
635     std::array<Real, 3> w{0,0,0};
636     gini = boost::math::statistics::sample_gini_coefficient(w);
637     BOOST_TEST(abs(gini) < tol);
638 }
639
640
641 template<class Real>
642 void test_gini_coefficient()
643 {
644     Real tol = std::numeric_limits<Real>::epsilon();
645     std::vector<Real> v{1,0,0};
646     Real gini = boost::math::statistics::gini_coefficient(v.begin(), v.end());
647     Real expected = Real(2)/Real(3);
648     BOOST_TEST(abs(gini - expected) < tol);
649
650     gini = boost::math::statistics::gini_coefficient(v);
651     BOOST_TEST(abs(gini - expected) < tol);
652
653     v[0] = 1;
654     v[1] = 1;
655     v[2] = 1;
656     gini = boost::math::statistics::gini_coefficient(v.begin(), v.end());
657     BOOST_TEST(abs(gini) < tol);
658
659     v[0] = 0;
660     v[1] = 0;
661     v[2] = 0;
662     gini = boost::math::statistics::gini_coefficient(v.begin(), v.end());
663     BOOST_TEST(abs(gini) < tol);
664
665     std::array<Real, 3> w{0,0,0};
666     gini = boost::math::statistics::gini_coefficient(w);
667     BOOST_TEST(abs(gini) < tol);
668
669     boost::numeric::ublas::vector<Real> w1(3);
670     w1[0] = 1;
671     w1[1] = 1;
672     w1[2] = 1;
673     gini = boost::math::statistics::gini_coefficient(w1);
674     BOOST_TEST(abs(gini) < tol);
675
676     std::mt19937 gen(18);
677     // Gini coefficient for a uniform distribution is (b-a)/(3*(b+a));
678     std::uniform_real_distribution<long double> dis(0, 3);
679     expected = (dis.b() - dis.a())/(3*(dis.b()+ dis.a()));
680     v.resize(1024);
681     for(size_t i = 0; i < v.size(); ++i)
682     {
683         v[i] = dis(gen);
684     }
685     gini = boost::math::statistics::gini_coefficient(v);
686     BOOST_TEST(abs(gini - expected) < 0.01);
687
688 }
689
690 template<class Z>
691 void test_integer_gini_coefficient()
692 {
693     double tol = std::numeric_limits<double>::epsilon();
694     std::vector<Z> v{1,0,0};
695     double gini = boost::math::statistics::gini_coefficient(v.begin(), v.end());
696     double expected = 2.0/3.0;
697     BOOST_TEST(abs(gini - expected) < tol);
698
699     gini = boost::math::statistics::gini_coefficient(v);
700     BOOST_TEST(abs(gini - expected) < tol);
701
702     v[0] = 1;
703     v[1] = 1;
704     v[2] = 1;
705     gini = boost::math::statistics::gini_coefficient(v.begin(), v.end());
706     BOOST_TEST(abs(gini) < tol);
707
708     v[0] = 0;
709     v[1] = 0;
710     v[2] = 0;
711     gini = boost::math::statistics::gini_coefficient(v.begin(), v.end());
712     BOOST_TEST(abs(gini) < tol);
713
714     std::array<Z, 3> w{0,0,0};
715     gini = boost::math::statistics::gini_coefficient(w);
716     BOOST_TEST(abs(gini) < tol);
717
718     boost::numeric::ublas::vector<Z> w1(3);
719     w1[0] = 1;
720     w1[1] = 1;
721     w1[2] = 1;
722     gini = boost::math::statistics::gini_coefficient(w1);
723     BOOST_TEST(abs(gini) < tol);
724 }
725
726 int main()
727 {
728     test_mean<float>();
729     test_mean<double>();
730     test_mean<long double>();
731     test_mean<cpp_bin_float_50>();
732
733     test_integer_mean<unsigned>();
734     test_integer_mean<int>();
735
736     test_complex_mean<std::complex<float>>();
737     test_complex_mean<cpp_complex_50>();
738
739     test_variance<float>();
740     test_variance<double>();
741     test_variance<long double>();
742     test_variance<cpp_bin_float_50>();
743
744     test_integer_variance<int>();
745     test_integer_variance<unsigned>();
746
747     test_skewness<float>();
748     test_skewness<double>();
749     test_skewness<long double>();
750     test_skewness<cpp_bin_float_50>();
751
752     test_integer_skewness<int>();
753     test_integer_skewness<unsigned>();
754
755     test_first_four_moments<float>();
756     test_first_four_moments<double>();
757     test_first_four_moments<long double>();
758     test_first_four_moments<cpp_bin_float_50>();
759
760     test_kurtosis<float>();
761     test_kurtosis<double>();
762     test_kurtosis<long double>();
763     // Kinda expensive:
764     //test_kurtosis<cpp_bin_float_50>();
765
766     test_integer_kurtosis<int>();
767     test_integer_kurtosis<unsigned>();
768
769     test_median<float>();
770     test_median<double>();
771     test_median<long double>();
772     test_median<cpp_bin_float_50>();
773     test_median<int>();
774
775     test_median_absolute_deviation<float>();
776     test_median_absolute_deviation<double>();
777     test_median_absolute_deviation<long double>();
778     test_median_absolute_deviation<cpp_bin_float_50>();
779
780     test_gini_coefficient<float>();
781     test_gini_coefficient<double>();
782     test_gini_coefficient<long double>();
783     test_gini_coefficient<cpp_bin_float_50>();
784
785     test_integer_gini_coefficient<unsigned>();
786     test_integer_gini_coefficient<int>();
787
788     test_sample_gini_coefficient<float>();
789     test_sample_gini_coefficient<double>();
790     test_sample_gini_coefficient<long double>();
791     test_sample_gini_coefficient<cpp_bin_float_50>();
792
793     return boost::report_errors();
794 }