Lumiera  0.pre.03
»edit your freedom«
statistic-test.cpp
Go to the documentation of this file.
1 /*
2  Statistic(Test) - validate simple statistic calculations
3 
4  Copyright (C) Lumiera.org
5  2009, Hermann Vosseler <Ichthyostega@web.de>
6 
7  This program is free software; you can redistribute it and/or
8  modify it under the terms of the GNU General Public License as
9  published by the Free Software Foundation; either version 2 of
10  the License, or (at your option) any later version.
11 
12  This program is distributed in the hope that it will be useful,
13  but WITHOUT ANY WARRANTY; without even the implied warranty of
14  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15  GNU General Public License for more details.
16 
17  You should have received a copy of the GNU General Public License
18  along with this program; if not, write to the Free Software
19  Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
20 
21 * *****************************************************/
22 
28 #include "lib/test/run.hpp"
29 #include "lib/test/test-helper.hpp"
30 #include "lib/stat/statistic.hpp"
31 #include "lib/iter-explorer.hpp"
32 #include "lib/format-util.hpp"
33 #include "lib/random.hpp"
34 #include "lib/util.hpp"
35 #include "lib/format-cout.hpp"
37 
38 
39 
40 namespace lib {
41 namespace stat{
42 namespace test{
43 
44  namespace {
45  const size_t NUM_POINTS = 1'000;
46  }
47 
48  using lib::test::roughEQ;
49  using util::isnil;
50  using error::LUMIERA_ERROR_INVALID;
51 
52 
53  /**************************************************************//**
54  * @test verifies the proper working of statistic helper functions.
55  * - calculate mean and standard derivation
56  * - one-dimensional linear regression
57  * @see DataCSV_test.hpp
58  * @see statistic.hpp
59  */
60  class Statistic_test : public Test
61  {
62  void
63  run (Arg)
64  {
65  demonstrate_DataSpan();
66  check_baseStatistics();
67  check_wightedLinearRegression();
68  check_TimeSeriesLinearRegression();
69  }
70 
71 
72 
74  void
75  demonstrate_DataSpan()
76  {
77  auto dat = VecD{0,1,2,3,4,5};
78 
79  DataSpan all{dat};
80  CHECK (not isnil (all));
81  CHECK (dat.size() == all.size());
82 
83  auto i = all.begin();
84  CHECK (i != all.end());
85  CHECK (0 == *i);
86  ++i;
87  CHECK (1 == *i);
88 
89  DataSpan innr{*i, dat.back()};
90  CHECK (util::join(innr) == "1, 2, 3, 4"_expect);
91  CHECK (2 == innr.at(1));
92  CHECK (2 == innr[1]);
93  CHECK (4 == innr[3]);
94  CHECK (5 == innr[4]); // »undefined behaviour«
95 
96  VERIFY_ERROR (INVALID, innr.at(4) )
97 
98  CHECK (1+2+3+4 == lib::explore(innr).resultSum());
99  }
100 
101 
103  void
104  check_baseStatistics ()
105  {
106  auto dat = VecD{4,2,5,8,6};
107  DataSpan all = lastN(dat, dat.size());
108  DataSpan rst = lastN(dat, 4);
109  CHECK (2 == *rst.begin());
110  CHECK (4 == rst.size());
111  CHECK (5 == all.size());
112 
113  CHECK (5.0 == average (all));
114  CHECK (5.25 == average(rst));
115 
116  // Surprise : divide by N-1 since it is a guess for the real standard derivation
117  CHECK (sdev (all, 5.0) == sqrt(20/(5-1)));
118 
119  CHECK (5.0 == averageLastN (dat,20));
120  CHECK (5.0 == averageLastN (dat, 5));
121  CHECK (5.25 == averageLastN (dat, 4));
122  CHECK (7.0 == averageLastN (dat, 2));
123  CHECK (6.0 == averageLastN (dat, 1));
124  CHECK (0.0 == averageLastN (dat, 0));
125  }
126 
127 
136  void
137  check_wightedLinearRegression()
138  {
139  RegressionData points{{1,1, 1}
140  ,{5,5, 1}
141  ,{3,1, 2}
142  };
143 
144  auto [socket,gradient
145  ,predicted,deltas
146  ,correlation
147  ,maxDelta
148  ,sdev] = computeLinearRegression (points);
149 
150  CHECK (socket == -1);
151  CHECK (gradient == 1);
152  CHECK (util::join (predicted) == "0, 4, 2"_expect );
153  CHECK (util::join (deltas) == "1, 1, -1"_expect );
154  CHECK (maxDelta == 1);
155  CHECK (correlation == "0.81649658"_expect );
156  CHECK (sdev == "1.7320508"_expect );
157  }
158 
159 
160 
165  void
166  check_TimeSeriesLinearRegression()
167  {
168  auto dirt = [] { return runi() - 0.5; };
169  auto fun = [&](uint i){ auto x = double(i)/NUM_POINTS;
170  return x*x;
171  };
172  VecD data;
173  data.reserve (NUM_POINTS);
174  for (uint i=0; i<NUM_POINTS; ++i)
175  data.push_back (fun(i) + dirt());
176 
177  auto [socket,gradient,correlation] = computeTimeSeriesLinearRegression (data);
178 
179  // regression line should roughly connect 0 to 1,
180  // yet slightly shifted downwards, cutting through the parabolic curve
181  CHECK (roughEQ (gradient*NUM_POINTS, 1, 0.08));
182  CHECK (roughEQ (socket, -0.16, 0.3 ));
183  CHECK (correlation > 0.65);
184  }
185  };
186 
187  LAUNCHER (Statistic_test, "unit calculation");
188 
189 
190 }}} // namespace lib::stat::test
191 
Automatically use custom string conversion in C++ stream output.
Definition: run.hpp:49
Helpers typically used while writing tests.
Implementation namespace for support and library code.
Simple test class runner.
Tiny helper functions and shortcuts to be used everywhere Consider this header to be effectively incl...
A collection of frequently used helper functions to support unit testing.
Generating (pseudo) random numbers with controlled seed.
Collection of small helpers and convenience shortcuts for diagnostics & formatting.
Building tree expanding and backtracking evaluations within hierarchical scopes.