source: trunk/test/fisher.cc @ 3743

Last change on this file since 3743 was 3743, checked in by Peter, 5 years ago

merge release 0.15.1 into trunk

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id
File size: 6.4 KB
Line 
1// $Id: fisher.cc 3743 2018-07-12 00:43:25Z peter $
2
3/*
4  Copyright (C) 2008, 2009, 2010, 2012, 2013, 2014, 2015, 2018 Peter Johansson
5
6  This file is part of the yat library, http://dev.thep.lu.se/yat
7
8  The yat library is free software; you can redistribute it and/or
9  modify it under the terms of the GNU General Public License as
10  published by the Free Software Foundation; either version 3 of the
11  License, or (at your option) any later version.
12
13  The yat library is distributed in the hope that it will be useful,
14  but WITHOUT ANY WARRANTY; without even the implied warranty of
15  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16  General Public License for more details.
17
18  You should have received a copy of the GNU General Public License
19  along with yat. If not, see <http://www.gnu.org/licenses/>.
20*/
21
22#include <config.h>
23
24#include "Suite.h"
25
26#include "yat/statistics/Fisher.h"
27
28#include <gsl/gsl_cdf.h>
29#include <gsl/gsl_randist.h>
30#include <climits>
31
32using namespace theplu::yat;
33void test_p_value(test::Suite&);
34void test_p_value_approximative(test::Suite&);
35void test_p_value_exact(test::Suite&);
36void test_large_numbers(test::Suite&);
37void test_yates(test::Suite&);
38void test_cdf_hypergeometric_Q(test::Suite&);
39void test_ticket908(test::Suite&);
40
41int main(int argc, char* argv[])
42{
43  test::Suite suite(argc, argv);
44
45  statistics::Fisher f;
46  if (!suite.equal(f.oddsratio(1,4,5,1), 0.05)) {
47    suite.add(false);
48    suite.err() << "oddsratio failed\n";
49  }
50  double a, b, c, d;
51  f.expected(a,b,c,d);
52  if (!suite.equal(a, 30.0/11.0)) {
53    suite.add(false);
54    suite.err() << "expected a failed\n";
55  }
56  if (!suite.equal(b, 25.0/11.0)) {
57    suite.add(false);
58    suite.err() << "expected b failed\n";
59  }
60  if (!suite.equal(c, 36.0/11.0)) {
61    suite.add(false);
62    suite.err() << "expected c failed\n";
63  }
64  if (!suite.equal(d, 30.0/11.0)) {
65    suite.add(false);
66    suite.err() << "expected d failed\n";
67  }
68  if (!suite.equal(f.Chi2(), 4.4122222222222222222222)) {
69    suite.add(false);
70    suite.err() << "Chi2 failed\n";
71  }
72  if (!suite.equal(f.minimum_size(),10)) {
73    suite.add(false);
74    suite.err() << "minimum_size failed\n";
75  }
76  test_p_value(suite);
77  test_large_numbers(suite);
78  test_yates(suite);
79  test_cdf_hypergeometric_Q(suite);
80  test_ticket908(suite);
81  return suite.return_value();
82}
83
84
85void test_large_numbers(test::Suite& suite)
86{
87  // skip test if unsigned int is 16 bit
88  if ((UINT_MAX >> 16) == 0) {
89    suite.out() << "skipping test_large_numbers\n";
90    return;
91  }
92
93  statistics::Fisher f;
94  double oddsratio = f.oddsratio(1166,63326825-1166,1095,66074759-1095);
95  if (oddsratio<0.5 || oddsratio>2) {
96    suite.err() << "oddsratio: " << oddsratio << "\n";
97    suite.err() << "expected ~ 1\n";
98    suite.add(false);
99  }
100  suite.add(suite.equal_fix(f.p_value(), 0.0123, 0.0001));
101  f.p_left();
102  f.p_right();
103}
104
105
106void test_p_value(test::Suite& suite)
107{
108  test_p_value_exact(suite);
109  test_p_value_approximative(suite);
110}
111
112
113void test_p_value_approximative(test::Suite& suite)
114{
115  suite.err() << "testing p_value_approximative\n";
116  statistics::Fisher f;
117  f.minimum_size() = 0;
118  f.oddsratio(10,20,20,50);
119  // oddsratio 1.25 > 1 so p = 2*p_right
120  suite.add(suite.equal(f.p_value(), 2*f.p_right()));
121  f.oddsratio(10,20,10,20);
122  suite.add(suite.equal(f.p_value(), 1.0));
123  suite.add(suite.equal(f.p_right(), 0.5));
124  suite.add(suite.equal(f.p_left(), 0.5));
125}
126
127
128void test_p_value_exact(test::Suite& suite)
129{
130  suite.err() << "test p_value_exact\n";
131  statistics::Fisher f;
132  f.minimum_size() = 1000;
133  f.oddsratio(10,20,10,20);
134  suite.add(suite.equal(f.p_value(), 1.0, 20));
135
136  f.oddsratio(10, 20, 20, 200);
137  suite.add(suite.equal_fix(f.p_value(), 0.000811906062767622,1e-16));
138  suite.add(suite.equal_fix(f.p_right(), 0.000811906062767622,1e-16));
139
140  // testing symmetry
141  statistics::Fisher f2;
142  f2.minimum_size() = 1000;
143  f2.oddsratio(20, 200, 10, 20);
144  suite.add(suite.equal(f2.p_value(), f.p_value()));
145  suite.add(suite.equal(f2.p_left(), f.p_right()));
146
147  f.oddsratio(1, 1, 1, 2);
148  suite.add(suite.equal(f.p_value(), 1.0, 2));
149  suite.add(suite.equal(f.p_right(), 0.7));
150  suite.add(suite.equal(f.p_left(), 0.9));
151
152  f.oddsratio(1, 1, 2, 1);
153  suite.add(suite.equal(f.p_value(), 1.0, 2));
154  suite.add(suite.equal(f.p_right(), 0.9));
155  suite.add(suite.equal(f.p_left(), 0.7));
156}
157
158
159void test_yates(test::Suite& suite)
160{
161  statistics::Fisher f;
162  statistics::Fisher f2(true);
163
164  f.oddsratio(5,10,10,10);
165  f2.oddsratio(5,10,10,10);
166  f.minimum_size() = 0;
167  f2.minimum_size() = 0;
168  double p = f.p_value();
169  double p_yates = f2.p_value();
170  if (p==p_yates) {
171    suite.add(false);
172    suite.err() << "p-value: " << p << "\n";
173    suite.err() << "p-value yates's corrected: " << p_yates << "\n";
174  }
175}
176
177
178void test_cdf_hypergeometric_Q(test::Suite& suite)
179{
180  suite.out() << "\ntest " << __func__ << "\n";
181  unsigned int n1 = 16;
182  unsigned int n2 = 3;
183  unsigned int t = 16;
184  for (unsigned int k=0; k<=t; ++k) {
185    // P(X=k)
186    double p = gsl_ran_hypergeometric_pdf(k, n1, n2, t);
187    // P(X<=k)
188    double P = gsl_cdf_hypergeometric_P(k, n1, n2, t);
189    // P(X>k)
190    double Q = gsl_cdf_hypergeometric_Q(k, n1, n2, t);
191    suite.out() << k << " " << p << " " << P << " " << Q << "\n";
192    double sum = 0;
193    for (unsigned int x=0; x<=k; ++x)
194      sum += gsl_ran_hypergeometric_pdf(x, n1, n2, t);
195    if (!suite.equal(sum, P, 20)) {
196      suite.add(false);
197      suite.err() << "error: gsl_cdf_hypergeometric_P for k=" << k << "\n";
198    }
199    if (!suite.equal(Q, 1-P, 1000)) {
200      suite.add(false);
201      suite.err() << "failed: Q = 1-P for k=" << k << "\n";
202    }
203  }
204}
205
206
207// test bug #908 reported in http://dev.thep.lu.se/yat/ticket/908
208void test_ticket908(test::Suite& suite)
209{
210  suite.out() << "===\ntesting ticket 908\n";
211  statistics::Fisher f;
212  int a1 = 13;
213  int a2 = 3;
214  int b1 = 3;
215  int b2 = 0;
216
217  double correct_p = 0;
218  unsigned int n1 = a1 + a2;
219  unsigned int n2 = b1 + b2;
220  unsigned int t = a1+b1;
221  for (unsigned int k=0; k<=n1; ++k) {
222    double P = gsl_ran_hypergeometric_pdf(k, n1, n2, t);
223    if (P <=  gsl_ran_hypergeometric_pdf(a1, n1, n2, t)) {
224      suite.out() << "counting " << k << " " << P << "\n";
225      correct_p += P;
226    }
227  }
228  statistics::Fisher fisher;
229  std::vector<double> p;
230  fisher.oddsratio(a1, a2, b1, b2);
231  p.push_back(fisher.p_value());
232  fisher.oddsratio(a2, a1, b2, b1);
233  p.push_back(fisher.p_value());
234  fisher.oddsratio(b1, b2, a1, a2);
235  p.push_back(fisher.p_value());
236  fisher.oddsratio(b2, b1, a2, a1);
237  p.push_back(fisher.p_value());
238  for (size_t i=0; i<p.size(); ++i) {
239    if (!suite.add(suite.equal(correct_p, p[i], 20)))
240      suite.err() << "error: incorrect p: " << p[i] << " for case "
241                  << i << "; expected: " << correct_p << "\n";
242  }
243}
Note: See TracBrowser for help on using the repository browser.