testMath.cc
Go to the documentation of this file.
1 
11 #include <utl/Math.h>
12 #include <utl/MathConstants.h>
13 #include <utl/BinomialCoefficients.h>
14 #include <utl/Polynomial.h>
15 
16 #include <tst/Verify.h>
17 #include <cppunit/extensions/HelperMacros.h>
18 
19 using namespace std;
20 using namespace utl;
21 using namespace tst;
22 
23 
24 #define EQUAL(x, y) CPPUNIT_ASSERT(Verify<Equal>(x, y))
25 #define CLOSE(x, y) CPPUNIT_ASSERT(Verify<CloseTo>(x, y))
26 #define CLOSEEPS(x, y, eps) CPPUNIT_ASSERT(Verify<CloseTo>(x, y, eps))
27 
28 
33 namespace std {
34  template<typename T>
35  ostream&
36  operator<<(ostream& os, const vector<T>& v)
37  {
38  copy(v.begin(), v.end(), ostream_iterator<T>(os, " "));
39  return os;
40  }
41 }
42 
43 
44 class MathTest : public CppUnit::TestFixture {
45 
46  CPPUNIT_TEST_SUITE(MathTest);
47  CPPUNIT_TEST(TestKolmogorovProbability);
48  CPPUNIT_TEST(TestInverseNormalCDF);
49  CPPUNIT_TEST(TestBinomialCoefficients);
50  CPPUNIT_TEST(TestLambertW);
51  CPPUNIT_TEST(TestChi2Probability);
52  CPPUNIT_TEST(TestChi2Probability2);
53  CPPUNIT_TEST(TestSign);
54  CPPUNIT_TEST(TestPolynomial);
55  CPPUNIT_TEST(TestEvalPoly);
56  CPPUNIT_TEST_SUITE_END();
57 
58 public:
59  void setUp() { }
60 
61  void tearDown() { }
62 
63  void
65  {
66  const double kolmDist = 0.75;
67  for (int i = 1; i <= 10; ++i)
68  cout << "KolmogorovProbability(" << i << ", " << kolmDist << ") = "
69  << KolmogorovProbability(i, kolmDist) << endl;
70  for (int i = 15; i <= 25; i += 5)
71  cout << "KolmogorovProbability(" << i << ", " << kolmDist << ") = "
72  << KolmogorovProbability(i, kolmDist) << endl;
73  for (int i = 30; i <= 50; i += 10)
74  cout << "KolmogorovProbability(" << i << ", " << kolmDist << ") = "
75  << KolmogorovProbability(i, kolmDist) << endl;
76  }
77 
78  void
80  {
81  const double deltap = 0.1;
82  for (double p = deltap; p <= 0.5; p += deltap) {
83  cout << "NormalDistribution (" << p << ") = "
84  << InverseNormalCDF(p) << endl;
85  const double sum = InverseNormalCDF(p) + InverseNormalCDF(1 - p);
86  const double identity = 0.5*(1 + erf(InverseNormalCDF(p)/kSqrt2));
87  cout << "InverseNormalDistribution (" << p << ") + InverseNormalDistribution (" << 1 - p << ") = "
88  << sum << endl;
89  cout << "erf(InverseNormalDistribution (" << p << ")) = "
90  << identity << endl;
91  CPPUNIT_ASSERT(Verify<CloseTo>(sum, 0.));
92  CPPUNIT_ASSERT(Verify<CloseTo>(identity, p));
93  }
94  }
95 
96  void
98  {
99  BinomialCoefficients& binomial = BinomialCoefficients::GetInstance();
100 
101  EQUAL(binomial(0, 0), 1.);
102  for (int n = 1; n <= 100; ++n) {
103  EQUAL(binomial(n, -10), 0.);
104  EQUAL(binomial(n, -1), 0.);
105  EQUAL(binomial(n, 0), 1.);
106  EQUAL(binomial(n, 1), double(n));
107  double sum = binomial(n, 0) + binomial(n, n);
108  double sum2 = 0*binomial(n, 0) + n*binomial(n, n);
109  for (int k = 1; k < n; ++k) {
110  sum += binomial(n, k);
111  sum2 += k * binomial(n, k);
112  // Pascal's rule
113  EQUAL(binomial(n, k), binomial(n-1, k-1) + binomial(n-1, k));
114  // symmetry
115  EQUAL(binomial(n, k), binomial(n, n - k));
116  // other relations
117  CLOSE(binomial(n, k), double(n)/k * binomial(n-1, k-1));
118  CLOSE((n-2*k)*binomial(n, k)/n, binomial(n-1, k) - binomial(n-1, k-1));
119  // Vandermonde's relation
120  for (int m = 0; m <= n; ++m) {
121  double sum3 = 0;
122  for (int j = 0; j <= n; ++j)
123  sum3 += binomial(m, j) * binomial(n-m, k-j);
124  CLOSE(sum3, binomial(n, k));
125  }
126  }
127  CLOSE(sum, pow(2., n));
128  CLOSE(sum2, n*pow(2., n-1));
129  EQUAL(binomial(n, n-1), double(n));
130  EQUAL(binomial(n, n), 1.);
131  EQUAL(binomial(n, n+1), 0.);
132  EQUAL(binomial(n, n+100), 0.);
133  }
134  }
135 
136  void
138  {
139  EQUAL(LambertW<0>(0), 0.);
140  // second order expansion around (0, 0)
141  for (double p = 10; p >= 3; p -= 0.1) {
142  const double x = pow(10., -p);
143  CLOSE(LambertW<0>(x), 0.5*(-1 + sqrt(1 + 4*x)));
144  CLOSE(LambertW<0>(-x), 0.5*(-1 + sqrt(1 - 4*x)));
145  }
146  // branch point
147  const double bp = -1 / kE;
148  CLOSE(LambertW<0>(bp), -1.);
149  CLOSE(LambertW<-1>(bp), -1.);
150  // expansion around branch point
151  for (double p = 10; p >= 4.5; p -= 0.1) {
152  const double eps = pow(10., -p);
153  const double x = bp + eps;
154  CLOSEEPS(LambertW<0>(x), -1 + sqrt(2*kE*eps), 1e-4);
155  CLOSEEPS(LambertW<-1>(x), -1 - sqrt(2*kE*eps), 1e-4);
156  }
157  // overall
158  for (double x = bp; x < 3; x += 0.01) {
159  const double y = LambertW<0>(x);
160  CLOSE(y*exp(y), x);
161  }
162  for (double t = 0; t < 20; t += 0.1) {
163  const double x = bp * exp(-t);
164  const double y = LambertW<-1>(x);
165  CLOSE(y*exp(y), x);
166  }
167  }
168 
169  void
171  {
172  // this crappy table is from http://en.wikipedia.org/wiki/Chi-squared_distribution
173  const unsigned int nNdof = 10;
174  const unsigned int nChi2 = 11;
175  const double chi2[][nChi2] = {
176  { },
177  { 0.004, 0.02, 0.06, 0.15, 0.46, 1.07, 1.64, 2.71, 3.84, 6.64, 10.83 }, // 1
178  { 0.10, 0.21, 0.45, 0.71, 1.39, 2.41, 3.22, 4.60, 5.99, 9.21, 13.82 }, // 2
179  { 0.35, 0.58, 1.01, 1.42, 2.37, 3.66, 4.64, 6.25, 7.82, 11.34, 16.27 }, // 3
180  { 0.71, 1.06, 1.65, 2.20, 3.36, 4.88, 5.99, 7.78, 9.49, 13.28, 18.47 }, // 4
181  { 1.14, 1.61, 2.34, 3.00, 4.35, 6.06, 7.29, 9.24, 11.07, 15.09, 20.52 }, // 5
182  { 1.63, 2.20, 3.07, 3.83, 5.35, 7.23, 8.56, 10.64, 12.59, 16.81, 22.46 }, // 6
183  { 2.17, 2.83, 3.82, 4.67, 6.35, 8.38, 9.80, 12.02, 14.07, 18.48, 24.32 }, // 7
184  { 2.73, 3.49, 4.59, 5.53, 7.34, 9.52, 11.03, 13.36, 15.51, 20.09, 26.12 }, // 8
185  { 3.32, 4.17, 5.38, 6.39, 8.34, 10.66, 12.24, 14.68, 16.92, 21.67, 27.88 }, // 9
186  { 3.94, 4.86, 6.18, 7.27, 9.34, 11.78, 13.44, 15.99, 18.31, 23.21, 29.59 } // 10
187  };
188  const double probability[nChi2] = {
189  0.95, 0.90, 0.80, 0.70, 0.50, 0.30, 0.20, 0.10, 0.05, 0.01, 0.001
190  };
191 
192  for (unsigned int ndof = 1; ndof <= nNdof; ++ndof)
193  for (unsigned int i = 0; i < nChi2; ++i)
194  CLOSEEPS(Chi2Probability(chi2[ndof][i], ndof), probability[i], 0.02);
195  }
196 
197  void
199  {
200  // this table was made with Mathematica function
201  // 2 InverseGammaRegularized[ndof/2, 0, 1 - probability]
202  const unsigned int nNdof = 10;
203  const unsigned int nChi2 = 11;
204  const double chi2[][nChi2] = {
205  { },
206  { 0.00393, 0.01579, 0.06418, 0.14847, 0.45494, 1.07419, 1.64237, 2.70554,
207  3.84146, 6.6349, 10.82757 },
208  { 0.10259, 0.21072, 0.44629, 0.71335, 1.38629, 2.40795, 3.21888, 4.60517,
209  5.99146, 9.21034, 13.81551 },
210  { 0.35185, 0.58437, 1.00517, 1.42365, 2.36597, 3.66487, 4.64163, 6.25139,
211  7.81473, 11.34487, 16.26624},
212  { 0.71072, 1.06362, 1.64878, 2.1947, 3.35669, 4.87843, 5.98862, 7.77944,
213  9.48773, 13.2767, 18.46683 },
214  { 1.14548, 1.61031, 2.34253, 2.99991, 4.35146, 6.06443, 7.28928, 9.23636,
215  11.0705, 15.08627, 20.51501},
216  { 1.63538, 2.20413, 3.07009, 3.82755, 5.34812, 7.23114, 8.55806, 10.64464,
217  12.59159, 16.81189, 22.45774 },
218  { 2.16735, 2.83311, 3.82232, 4.67133, 6.34581, 8.38343, 9.80325, 12.01704,
219  14.06714, 18.47531, 24.32189},
220  { 2.73264, 3.48954, 4.59357, 5.52742, 7.34412, 9.52446, 11.03009, 13.36157,
221  15.50731, 20.09024, 26.12448},
222  { 3.32511, 4.16816, 5.38005, 6.39331, 8.34283, 10.65637, 12.24215, 14.68366,
223  16.91898, 21.66599, 27.87716 },
224  { 3.9403, 4.86518, 6.17908, 7.26722, 9.34182, 11.78072, 13.44196, 15.98718,
225  18.30704, 23.20925, 29.5883 }
226  };
227  const double probability[nChi2] = {
228  0.95, 0.90, 0.80, 0.70, 0.50, 0.30, 0.20, 0.10, 0.05, 0.01, 0.001
229  };
230 
231  for (unsigned int ndof = 1; ndof <= nNdof; ++ndof)
232  for (unsigned int i = 0; i < nChi2; ++i)
233  CLOSEEPS(Chi2Probability(chi2[ndof][i], ndof), probability[i], 1e-4);
234  }
235 
236  void
238  {
239  unsigned int ui = 0;
240  EQUAL(Sign(ui), 0);
241  ui = 1;
242  EQUAL(Sign(ui), 1);
243  int i = -1;
244  EQUAL(Sign(i), -1);
245  i = 0;
246  EQUAL(Sign(i), 0);
247  i = 1;
248  EQUAL(Sign(i), 1);
249  i = 100;
250  EQUAL(Sign(i), 1);
251  i = -100;
252  EQUAL(Sign(i), -1);
253  double d = -2;
254  EQUAL(Sign(d), -1);
255  d = 0;
256  EQUAL(Sign(d), 0);
257  d = 1e19;
258  EQUAL(Sign(d), 1);
259  }
260 
261  void
263  {
264  const double coeff[] = { 1, 2, 3, 4, 5 };
265  const Polynomial p(coeff);
266  CPPUNIT_ASSERT(p);
267  for (unsigned int i = 0; i < Length(coeff); ++i)
268  EQUAL(p.GetCoefficients()[i], coeff[i]);
269  const double res[] = { 1, 15, 129, 547, 1593, 3711, 7465, 13539, 22737, 35983 };
270  for (int i = 0; i < 10; ++i)
271  CLOSE(p(i), res[i]);
272  const int intCoeff[] = { 1, 2, 3, 4, 5 };
273  const Polynomial q(intCoeff);
274  for (int i = 0; i < 10; ++i)
275  CLOSE(q(i), res[i]);
276  cout << q << endl;
277  stringstream ss;
278  ss << q;
279  Polynomial r;
280  CPPUNIT_ASSERT(!r);
281  cout << ss.str() << endl;
282  ss >> r;
283  CPPUNIT_ASSERT(r);
284  EQUAL(q.GetCoefficients(), r.GetCoefficients());
285  }
286 
287  void
289  {
290  const double res[] = { 1, 15, 129, 547, 1593, 3711, 7465, 13539, 22737, 35983 };
291  // test initializer_list<int>
292  for (int i = 0; i < 10; ++i)
293  CLOSE(EvalPoly({1, 2, 3, 4, 5}, i), res[i]);
294  // test initializer_list<double>
295  for (int i = 0; i < 10; ++i)
296  CLOSE(EvalPoly({1., 2., 3., 4., 5.}, i), res[i]);
297  {
298  // test vector<double>
299  const vector<double> coeff({1, 2, 3, 4, 5});
300  for (int i = 0; i < 10; ++i)
301  CLOSE(EvalPoly(coeff, i), res[i]);
302  }
303  {
304  // test vector<int>
305  const vector<int> coeff({1, 2, 3, 4, 5});
306  for (int i = 0; i < 10; ++i)
307  CLOSE(EvalPoly(coeff, i), res[i]);
308  }
309  {
310  // test temporary vector<double>
311  for (int i = 0; i < 10; ++i)
312  CLOSE(EvalPoly(vector<double>({1, 2, 3, 4, 5}), i), res[i]);
313  }
314  {
315  // test temporary vector<int>
316  for (int i = 0; i < 10; ++i)
317  CLOSE(EvalPoly(vector<int>({1, 2, 3, 4, 5}), i), res[i]);
318  }
319  {
320  // test double c-array
321  const double coeff[] = { 1, 2, 3, 4, 5 };
322  for (int i = 0; i < 10; ++i)
323  CLOSE(EvalPoly(coeff, i), res[i]);
324  }
325  {
326  // test int c-array
327  const int coeff[] = { 1, 2, 3, 4, 5 };
328  for (int i = 0; i < 10; ++i)
329  CLOSE(EvalPoly(coeff, i), res[i]);
330  }
331  }
332 
333 };
334 
335 
void TestBinomialCoefficients()
Definition: testMath.cc:97
constexpr double kE
Definition: MathConstants.h:28
Simple polynomial container.
Definition: Polynomial.h:22
#define CLOSE(x, y)
Definition: testMath.cc:25
void setUp()
Definition: testMath.cc:59
double LambertW< 0 >(const double x)
Definition: LambertW.cc:559
void TestChi2Probability()
Definition: testMath.cc:170
void TestChi2Probability2()
Definition: testMath.cc:198
double pow(const double x, const unsigned int i)
double InverseNormalCDF(const double p)
Inverse of the comulative normal distribution. Taken from http://home.online.no/~pjacklam/notes/invno...
CPPUNIT_TEST_SUITE_REGISTRATION(testAiresShowerFile)
void tearDown()
Definition: testMath.cc:61
void TestEvalPoly()
Definition: testMath.cc:288
void TestInverseNormalCDF()
Definition: testMath.cc:79
double EvalPoly(const T &a, const double x)
Simple polynomial evaluator.
double LambertW(const double x)
void TestKolmogorovProbability()
Definition: testMath.cc:64
double eps
constexpr double kSqrt2
Definition: MathConstants.h:30
double KolmogorovProbability(const double effectiveN, const double kolmogorovDistance)
Definition: Kolmogorov.cc:10
void TestPolynomial()
Definition: testMath.cc:262
const std::vector< double > & GetCoefficients() const
Definition: Polynomial.h:34
#define CLOSEEPS(x, y, eps)
Definition: testMath.cc:26
constexpr int Sign(const T x, const boost::integral_constant< bool, false >)
#define EQUAL(x, y)
Definition: testMath.cc:24
double Chi2Probability(const double chi2, const double ndof)
double LambertW<-1 >(const double x)
Definition: LambertW.cc:573
void TestLambertW()
Definition: testMath.cc:137
constexpr double m
Definition: AugerUnits.h:121
Calculates binomial coefficients and caches the results.
void TestSign()
Definition: testMath.cc:237

, generated on Tue Sep 26 2023.