test_prob_distr.c 43 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078107910801081108210831084108510861087108810891090109110921093109410951096109710981099110011011102110311041105110611071108110911101111111211131114111511161117111811191120112111221123112411251126112711281129113011311132113311341135113611371138113911401141114211431144114511461147114811491150115111521153115411551156115711581159116011611162116311641165116611671168116911701171117211731174117511761177117811791180118111821183118411851186118711881189119011911192119311941195119611971198119912001201120212031204120512061207120812091210121112121213121412151216121712181219122012211222122312241225122612271228122912301231123212331234123512361237123812391240124112421243124412451246124712481249125012511252125312541255125612571258125912601261126212631264126512661267126812691270127112721273127412751276127712781279128012811282128312841285128612871288128912901291129212931294129512961297129812991300130113021303130413051306130713081309131013111312131313141315131613171318131913201321132213231324132513261327132813291330133113321333133413351336133713381339134013411342134313441345134613471348134913501351135213531354135513561357135813591360136113621363136413651366136713681369137013711372137313741375137613771378137913801381138213831384138513861387138813891390139113921393139413951396139713981399140014011402
  1. /* Copyright (c) 2018-2019, The Tor Project, Inc. */
  2. /* See LICENSE for licensing information */
  3. /**
  4. * \file test_prob_distr.c
  5. * \brief Test probability distributions.
  6. * \detail
  7. *
  8. * For each probability distribution we do two kinds of tests:
  9. *
  10. * a) We do numerical deterministic testing of their cdf/icdf/sf/isf functions
  11. * and the various relationships between them for each distribution. We also
  12. * do deterministic tests on their sampling functions. Test vectors for
  13. * these tests were computed from alternative implementations and were
  14. * eyeballed to make sure they make sense
  15. * (e.g. src/test/prob_distr_mpfr_ref.c computes logit(p) using GNU mpfr
  16. * with 200-bit precision and is then tested in test_logit_logistic()).
  17. *
  18. * b) We do stochastic hypothesis testing (G-test) to ensure that sampling from
  19. * the given distributions is distributed properly. The stochastic tests are
  20. * slow and their false positive rate is not well suited for CI, so they are
  21. * currently disabled-by-default and put into 'tests-slow'.
  22. */
  23. #define PROB_DISTR_PRIVATE
  24. #include "orconfig.h"
  25. #include "test/test.h"
  26. #include "core/or/or.h"
  27. #include "lib/math/prob_distr.h"
  28. #include "lib/math/fp.h"
  29. #include "lib/crypt_ops/crypto_rand.h"
  30. #include "test/rng_test_helpers.h"
  31. #include <float.h>
  32. #include <math.h>
  33. #include <stdbool.h>
  34. #include <stddef.h>
  35. #include <stdint.h>
  36. #include <stdio.h>
  37. #include <stdlib.h>
  38. /**
  39. * Return floor(d) converted to size_t, as a workaround for complaints
  40. * under -Wbad-function-cast for (size_t)floor(d).
  41. */
  42. static size_t
  43. floor_to_size_t(double d)
  44. {
  45. double integral_d = floor(d);
  46. return (size_t)integral_d;
  47. }
  48. /**
  49. * Return ceil(d) converted to size_t, as a workaround for complaints
  50. * under -Wbad-function-cast for (size_t)ceil(d).
  51. */
  52. static size_t
  53. ceil_to_size_t(double d)
  54. {
  55. double integral_d = ceil(d);
  56. return (size_t)integral_d;
  57. }
  58. /*
  59. * Geometric(p) distribution, supported on {1, 2, 3, ...}.
  60. *
  61. * Compute the probability mass function Geom(n; p) of the number of
  62. * trials before the first success when success has probability p.
  63. */
  64. static double
  65. logpmf_geometric(unsigned n, double p)
  66. {
  67. /* This is actually a check against 1, but we do >= so that the compiler
  68. does not raise a -Wfloat-equal */
  69. if (p >= 1) {
  70. if (n == 1)
  71. return 0;
  72. else
  73. return -HUGE_VAL;
  74. }
  75. return (n - 1)*log1p(-p) + log(p);
  76. }
  77. /**
  78. * Compute the logistic function, translated in output by 1/2:
  79. * logistichalf(x) = logistic(x) - 1/2. Well-conditioned on the entire
  80. * real plane, with maximum condition number 1 at 0.
  81. *
  82. * This implementation gives relative error bounded by 5 eps.
  83. */
  84. static double
  85. logistichalf(double x)
  86. {
  87. /*
  88. * Rewrite this with the identity
  89. *
  90. * 1/(1 + e^{-x}) - 1/2
  91. * = (1 - 1/2 - e^{-x}/2)/(1 + e^{-x})
  92. * = (1/2 - e^{-x}/2)/(1 + e^{-x})
  93. * = (1 - e^{-x})/[2 (1 + e^{-x})]
  94. * = -(e^{-x} - 1)/[2 (1 + e^{-x})],
  95. *
  96. * which we can evaluate by -expm1(-x)/[2 (1 + exp(-x))].
  97. *
  98. * Suppose exp has error d0, + has error d1, expm1 has error
  99. * d2, and / has error d3, so we evaluate
  100. *
  101. * -(1 + d2) (1 + d3) (e^{-x} - 1)
  102. * / [2 (1 + d1) (1 + (1 + d0) e^{-x})].
  103. *
  104. * In the denominator,
  105. *
  106. * 1 + (1 + d0) e^{-x}
  107. * = 1 + e^{-x} + d0 e^{-x}
  108. * = (1 + e^{-x}) (1 + d0 e^{-x}/(1 + e^{-x})),
  109. *
  110. * so the relative error of the numerator is
  111. *
  112. * d' = d2 + d3 + d2 d3,
  113. * and of the denominator,
  114. * d'' = d1 + d0 e^{-x}/(1 + e^{-x}) + d0 d1 e^{-x}/(1 + e^{-x})
  115. * = d1 + d0 L(-x) + d0 d1 L(-x),
  116. *
  117. * where L(-x) is logistic(-x). By Lemma 1 the relative error
  118. * of the quotient is bounded by
  119. *
  120. * 2|d2 + d3 + d2 d3 - d1 - d0 L(x) + d0 d1 L(x)|,
  121. *
  122. * Since 0 < L(x) < 1, this is bounded by
  123. *
  124. * 2|d2| + 2|d3| + 2|d2 d3| + 2|d1| + 2|d0| + 2|d0 d1|
  125. * <= 4 eps + 2 eps^2.
  126. */
  127. if (x < log(DBL_EPSILON/8)) {
  128. /*
  129. * Avoid overflow in e^{-x}. When x < log(eps/4), we
  130. * we further have x < logit(eps/4), so that
  131. * logistic(x) < eps/4. Hence the relative error of
  132. * logistic(x) - 1/2 from -1/2 is bounded by eps/2, and
  133. * so the relative error of -1/2 from logistic(x) - 1/2
  134. * is bounded by eps.
  135. */
  136. return -0.5;
  137. } else {
  138. return -expm1(-x)/(2*(1 + exp(-x)));
  139. }
  140. }
  141. /**
  142. * Compute the log of the sum of the exps. Caller should arrange the
  143. * array in descending order to minimize error because I don't want to
  144. * deal with using temporary space and the one caller in this file
  145. * arranges that anyway.
  146. *
  147. * Warning: This implementation does not handle infinite or NaN inputs
  148. * sensibly, because I don't need that here at the moment. (NaN, or
  149. * -inf and +inf together, should yield NaN; +inf and finite should
  150. * yield +inf; otherwise all -inf should be ignored because exp(-inf) =
  151. * 0.)
  152. */
  153. static double
  154. logsumexp(double *A, size_t n)
  155. {
  156. double maximum, sum;
  157. size_t i;
  158. if (n == 0)
  159. return log(0);
  160. maximum = A[0];
  161. for (i = 1; i < n; i++) {
  162. if (A[i] > maximum)
  163. maximum = A[i];
  164. }
  165. sum = 0;
  166. for (i = n; i --> 0;)
  167. sum += exp(A[i] - maximum);
  168. return log(sum) + maximum;
  169. }
  170. /**
  171. * Compute log(1 - e^x). Defined only for negative x so that e^x < 1.
  172. * This is the complement of a probability in log space.
  173. */
  174. static double
  175. log1mexp(double x)
  176. {
  177. /*
  178. * We want to compute log on [0, 1/2) but log1p on [1/2, +inf),
  179. * so partition x at -log(2) = log(1/2).
  180. */
  181. if (-log(2) < x)
  182. return log(-expm1(x));
  183. else
  184. return log1p(-exp(x));
  185. }
  186. /*
  187. * Tests of numerical errors in computing logit, logistic, and the
  188. * various cdfs, sfs, icdfs, and isfs.
  189. */
  190. #define arraycount(A) (sizeof(A)/sizeof(A[0]))
  191. /** Return relative error between <b>actual</b> and <b>expected</b>.
  192. * Special cases: If <b>expected</b> is zero or infinite, return 1 if
  193. * <b>actual</b> is equal to <b>expected</b> and 0 if not, since the
  194. * usual notion of relative error is undefined but we only use this
  195. * for testing relerr(e, a) <= bound. If either is NaN, return NaN,
  196. * which has the property that NaN <= bound is false no matter what
  197. * bound is.
  198. *
  199. * Beware: if you test !(relerr(e, a) > bound), then then the result
  200. * is true when a is NaN because NaN > bound is false too. See
  201. * CHECK_RELERR for correct use to decide when to report failure.
  202. */
  203. static double
  204. relerr(double expected, double actual)
  205. {
  206. /*
  207. * To silence -Wfloat-equal, we have to test for equality using
  208. * inequalities: we have (fabs(expected) <= 0) iff (expected == 0),
  209. * and (actual <= expected && actual >= expected) iff actual ==
  210. * expected whether expected is zero or infinite.
  211. */
  212. if (fabs(expected) <= 0 || tor_isinf(expected)) {
  213. if (actual <= expected && actual >= expected)
  214. return 0;
  215. else
  216. return 1;
  217. } else {
  218. return fabs((expected - actual)/expected);
  219. }
  220. }
  221. /** Check that relative error of <b>expected</b> and <b>actual</b> is within
  222. * <b>relerr_bound</b>. Caller must arrange to have i and relerr_bound in
  223. * scope. */
  224. #define CHECK_RELERR(expected, actual) do { \
  225. double check_expected = (expected); \
  226. double check_actual = (actual); \
  227. const char *str_expected = #expected; \
  228. const char *str_actual = #actual; \
  229. double check_relerr = relerr(expected, actual); \
  230. if (!(relerr(check_expected, check_actual) <= relerr_bound)) { \
  231. log_warn(LD_GENERAL, "%s:%d: case %u: relerr(%s=%.17e, %s=%.17e)" \
  232. " = %.17e > %.17e\n", \
  233. __func__, __LINE__, (unsigned) i, \
  234. str_expected, check_expected, \
  235. str_actual, check_actual, \
  236. check_relerr, relerr_bound); \
  237. ok = false; \
  238. } \
  239. } while (0)
  240. /* Check that a <= b.
  241. * Caller must arrange to have i in scope. */
  242. #define CHECK_LE(a, b) do { \
  243. double check_a = (a); \
  244. double check_b = (b); \
  245. const char *str_a = #a; \
  246. const char *str_b = #b; \
  247. if (!(check_a <= check_b)) { \
  248. log_warn(LD_GENERAL, "%s:%d: case %u: %s=%.17e > %s=%.17e\n", \
  249. __func__, __LINE__, (unsigned) i, \
  250. str_a, check_a, str_b, check_b); \
  251. ok = false; \
  252. } \
  253. } while (0)
  254. /**
  255. * Test the logit and logistic functions. Confirm that they agree with
  256. * the cdf, sf, icdf, and isf of the standard Logistic distribution.
  257. * Confirm that the sampler for the standard logistic distribution maps
  258. * [0, 1] into the right subinterval for the inverse transform, for
  259. * this implementation.
  260. */
  261. static void
  262. test_logit_logistic(void *arg)
  263. {
  264. (void) arg;
  265. static const struct {
  266. double x; /* x = logit(p) */
  267. double p; /* p = logistic(x) */
  268. double phalf; /* p - 1/2 = logistic(x) - 1/2 */
  269. } cases[] = {
  270. { -HUGE_VAL, 0, -0.5 },
  271. { -1000, 0, -0.5 },
  272. { -710, 4.47628622567513e-309, -0.5 },
  273. { -708, 3.307553003638408e-308, -0.5 },
  274. { -2, .11920292202211755, -.3807970779778824 },
  275. { -1.0000001, .2689414017088022, -.23105859829119776 },
  276. { -1, .2689414213699951, -.23105857863000487 },
  277. { -0.9999999, .26894144103118883, -.2310585589688111 },
  278. /* see src/test/prob_distr_mpfr_ref.c for computation */
  279. { -4.000000000537333e-5, .49999, -1.0000000000010001e-5 },
  280. { -4.000000000533334e-5, .49999, -.00001 },
  281. { -4.000000108916878e-9, .499999999, -1.0000000272292198e-9 },
  282. { -4e-9, .499999999, -1e-9 },
  283. { -4e-16, .5, -1e-16 },
  284. { -4e-300, .5, -1e-300 },
  285. { 0, .5, 0 },
  286. { 4e-300, .5, 1e-300 },
  287. { 4e-16, .5, 1e-16 },
  288. { 3.999999886872274e-9, .500000001, 9.999999717180685e-10 },
  289. { 4e-9, .500000001, 1e-9 },
  290. { 4.0000000005333336e-5, .50001, .00001 },
  291. { 8.000042667076272e-3, .502, .002 },
  292. { 0.9999999, .7310585589688111, .2310585589688111 },
  293. { 1, .7310585786300049, .23105857863000487 },
  294. { 1.0000001, .7310585982911977, .23105859829119774 },
  295. { 2, .8807970779778823, .3807970779778824 },
  296. { 708, 1, .5 },
  297. { 710, 1, .5 },
  298. { 1000, 1, .5 },
  299. { HUGE_VAL, 1, .5 },
  300. };
  301. double relerr_bound = 3e-15; /* >10eps */
  302. size_t i;
  303. bool ok = true;
  304. for (i = 0; i < arraycount(cases); i++) {
  305. double x = cases[i].x;
  306. double p = cases[i].p;
  307. double phalf = cases[i].phalf;
  308. /*
  309. * cdf is logistic, icdf is logit, and symmetry for
  310. * sf/isf.
  311. */
  312. CHECK_RELERR(logistic(x), cdf_logistic(x, 0, 1));
  313. CHECK_RELERR(logistic(-x), sf_logistic(x, 0, 1));
  314. CHECK_RELERR(logit(p), icdf_logistic(p, 0, 1));
  315. CHECK_RELERR(-logit(p), isf_logistic(p, 0, 1));
  316. CHECK_RELERR(cdf_logistic(x, 0, 1), cdf_logistic(x*2, 0, 2));
  317. CHECK_RELERR(sf_logistic(x, 0, 1), sf_logistic(x*2, 0, 2));
  318. CHECK_RELERR(icdf_logistic(p, 0, 1), icdf_logistic(p, 0, 2)/2);
  319. CHECK_RELERR(isf_logistic(p, 0, 1), isf_logistic(p, 0, 2)/2);
  320. CHECK_RELERR(cdf_logistic(x, 0, 1), cdf_logistic(x/2, 0, .5));
  321. CHECK_RELERR(sf_logistic(x, 0, 1), sf_logistic(x/2, 0, .5));
  322. CHECK_RELERR(icdf_logistic(p, 0, 1), icdf_logistic(p, 0,.5)*2);
  323. CHECK_RELERR(isf_logistic(p, 0, 1), isf_logistic(p, 0, .5)*2);
  324. CHECK_RELERR(cdf_logistic(x, 0, 1), cdf_logistic(x*2 + 1, 1, 2));
  325. CHECK_RELERR(sf_logistic(x, 0, 1), sf_logistic(x*2 + 1, 1, 2));
  326. /*
  327. * For p near 0 and p near 1/2, the arithmetic of
  328. * translating by 1 loses precision.
  329. */
  330. if (fabs(p) > DBL_EPSILON && fabs(p) < 0.4) {
  331. CHECK_RELERR(icdf_logistic(p, 0, 1),
  332. (icdf_logistic(p, 1, 2) - 1)/2);
  333. CHECK_RELERR(isf_logistic(p, 0, 1),
  334. (isf_logistic(p, 1, 2) - 1)/2);
  335. }
  336. CHECK_RELERR(p, logistic(x));
  337. CHECK_RELERR(phalf, logistichalf(x));
  338. /*
  339. * On the interior floating-point numbers, either logit or
  340. * logithalf had better give the correct answer.
  341. *
  342. * For probabilities near 0, we can get much finer resolution with
  343. * logit, and for probabilities near 1/2, we can get much finer
  344. * resolution with logithalf by representing them using p - 1/2.
  345. *
  346. * E.g., we can write -.00001 for phalf, and .49999 for p, but the
  347. * difference 1/2 - .00001 gives 1.0000000000010001e-5 in binary64
  348. * arithmetic. So test logit(.49999) which should give the same
  349. * answer as logithalf(-1.0000000000010001e-5), namely
  350. * -4.000000000537333e-5, and also test logithalf(-.00001) which
  351. * gives -4.000000000533334e-5 instead -- but don't expect
  352. * logit(.49999) to give -4.000000000533334e-5 even though it looks
  353. * like 1/2 - .00001.
  354. *
  355. * A naive implementation of logit will just use log(p/(1 - p)) and
  356. * give the answer -4.000000000551673e-05 for .49999, which is
  357. * wrong in a lot of digits, which happens because log is
  358. * ill-conditioned near 1 and thus amplifies whatever relative
  359. * error we made in computing p/(1 - p).
  360. */
  361. if ((0 < p && p < 1) || tor_isinf(x)) {
  362. if (phalf >= p - 0.5 && phalf <= p - 0.5)
  363. CHECK_RELERR(x, logit(p));
  364. if (p >= 0.5 + phalf && p <= 0.5 + phalf)
  365. CHECK_RELERR(x, logithalf(phalf));
  366. }
  367. CHECK_RELERR(-phalf, logistichalf(-x));
  368. if (fabs(phalf) < 0.5 || tor_isinf(x))
  369. CHECK_RELERR(-x, logithalf(-phalf));
  370. if (p < 1 || tor_isinf(x)) {
  371. CHECK_RELERR(1 - p, logistic(-x));
  372. if (p > .75 || tor_isinf(x))
  373. CHECK_RELERR(-x, logit(1 - p));
  374. } else {
  375. CHECK_LE(logistic(-x), 1e-300);
  376. }
  377. }
  378. for (i = 0; i <= 100; i++) {
  379. double p0 = (double)i/100;
  380. CHECK_RELERR(logit(p0/(1 + M_E)), sample_logistic(0, 0, p0));
  381. CHECK_RELERR(-logit(p0/(1 + M_E)), sample_logistic(1, 0, p0));
  382. CHECK_RELERR(logithalf(p0*(0.5 - 1/(1 + M_E))),
  383. sample_logistic(0, 1, p0));
  384. CHECK_RELERR(-logithalf(p0*(0.5 - 1/(1 + M_E))),
  385. sample_logistic(1, 1, p0));
  386. }
  387. if (!ok)
  388. printf("fail logit/logistic / logistic cdf/sf\n");
  389. tt_assert(ok);
  390. done:
  391. ;
  392. }
  393. /**
  394. * Test the cdf, sf, icdf, and isf of the LogLogistic distribution.
  395. */
  396. static void
  397. test_log_logistic(void *arg)
  398. {
  399. (void) arg;
  400. static const struct {
  401. /* x is a point in the support of the LogLogistic distribution */
  402. double x;
  403. /* 'p' is the probability that a random variable X for a given LogLogistic
  404. * probability ditribution will take value less-or-equal to x */
  405. double p;
  406. /* 'np' is the probability that a random variable X for a given LogLogistic
  407. * probability distribution will take value greater-or-equal to x. */
  408. double np;
  409. } cases[] = {
  410. { 0, 0, 1 },
  411. { 1e-300, 1e-300, 1 },
  412. { 1e-17, 1e-17, 1 },
  413. { 1e-15, 1e-15, .999999999999999 },
  414. { .1, .09090909090909091, .90909090909090909 },
  415. { .25, .2, .8 },
  416. { .5, .33333333333333333, .66666666666666667 },
  417. { .75, .42857142857142855, .5714285714285714 },
  418. { .9999, .49997499874993756, .5000250012500626 },
  419. { .99999999, .49999999749999996, .5000000025 },
  420. { .999999999999999, .49999999999999994, .5000000000000002 },
  421. { 1, .5, .5 },
  422. };
  423. double relerr_bound = 3e-15;
  424. size_t i;
  425. bool ok = true;
  426. for (i = 0; i < arraycount(cases); i++) {
  427. double x = cases[i].x;
  428. double p = cases[i].p;
  429. double np = cases[i].np;
  430. CHECK_RELERR(p, cdf_log_logistic(x, 1, 1));
  431. CHECK_RELERR(p, cdf_log_logistic(x/2, .5, 1));
  432. CHECK_RELERR(p, cdf_log_logistic(x*2, 2, 1));
  433. CHECK_RELERR(p, cdf_log_logistic(sqrt(x), 1, 2));
  434. CHECK_RELERR(p, cdf_log_logistic(sqrt(x)/2, .5, 2));
  435. CHECK_RELERR(p, cdf_log_logistic(sqrt(x)*2, 2, 2));
  436. if (2*sqrt(DBL_MIN) < x) {
  437. CHECK_RELERR(p, cdf_log_logistic(x*x, 1, .5));
  438. CHECK_RELERR(p, cdf_log_logistic(x*x/2, .5, .5));
  439. CHECK_RELERR(p, cdf_log_logistic(x*x*2, 2, .5));
  440. }
  441. CHECK_RELERR(np, sf_log_logistic(x, 1, 1));
  442. CHECK_RELERR(np, sf_log_logistic(x/2, .5, 1));
  443. CHECK_RELERR(np, sf_log_logistic(x*2, 2, 1));
  444. CHECK_RELERR(np, sf_log_logistic(sqrt(x), 1, 2));
  445. CHECK_RELERR(np, sf_log_logistic(sqrt(x)/2, .5, 2));
  446. CHECK_RELERR(np, sf_log_logistic(sqrt(x)*2, 2, 2));
  447. if (2*sqrt(DBL_MIN) < x) {
  448. CHECK_RELERR(np, sf_log_logistic(x*x, 1, .5));
  449. CHECK_RELERR(np, sf_log_logistic(x*x/2, .5, .5));
  450. CHECK_RELERR(np, sf_log_logistic(x*x*2, 2, .5));
  451. }
  452. CHECK_RELERR(np, cdf_log_logistic(1/x, 1, 1));
  453. CHECK_RELERR(np, cdf_log_logistic(1/(2*x), .5, 1));
  454. CHECK_RELERR(np, cdf_log_logistic(2/x, 2, 1));
  455. CHECK_RELERR(np, cdf_log_logistic(1/sqrt(x), 1, 2));
  456. CHECK_RELERR(np, cdf_log_logistic(1/(2*sqrt(x)), .5, 2));
  457. CHECK_RELERR(np, cdf_log_logistic(2/sqrt(x), 2, 2));
  458. if (2*sqrt(DBL_MIN) < x && x < 1/(2*sqrt(DBL_MIN))) {
  459. CHECK_RELERR(np, cdf_log_logistic(1/(x*x), 1, .5));
  460. CHECK_RELERR(np, cdf_log_logistic(1/(2*x*x), .5, .5));
  461. CHECK_RELERR(np, cdf_log_logistic(2/(x*x), 2, .5));
  462. }
  463. CHECK_RELERR(p, sf_log_logistic(1/x, 1, 1));
  464. CHECK_RELERR(p, sf_log_logistic(1/(2*x), .5, 1));
  465. CHECK_RELERR(p, sf_log_logistic(2/x, 2, 1));
  466. CHECK_RELERR(p, sf_log_logistic(1/sqrt(x), 1, 2));
  467. CHECK_RELERR(p, sf_log_logistic(1/(2*sqrt(x)), .5, 2));
  468. CHECK_RELERR(p, sf_log_logistic(2/sqrt(x), 2, 2));
  469. if (2*sqrt(DBL_MIN) < x && x < 1/(2*sqrt(DBL_MIN))) {
  470. CHECK_RELERR(p, sf_log_logistic(1/(x*x), 1, .5));
  471. CHECK_RELERR(p, sf_log_logistic(1/(2*x*x), .5, .5));
  472. CHECK_RELERR(p, sf_log_logistic(2/(x*x), 2, .5));
  473. }
  474. CHECK_RELERR(x, icdf_log_logistic(p, 1, 1));
  475. CHECK_RELERR(x/2, icdf_log_logistic(p, .5, 1));
  476. CHECK_RELERR(x*2, icdf_log_logistic(p, 2, 1));
  477. CHECK_RELERR(x, icdf_log_logistic(p, 1, 1));
  478. CHECK_RELERR(sqrt(x)/2, icdf_log_logistic(p, .5, 2));
  479. CHECK_RELERR(sqrt(x)*2, icdf_log_logistic(p, 2, 2));
  480. CHECK_RELERR(sqrt(x), icdf_log_logistic(p, 1, 2));
  481. CHECK_RELERR(x*x/2, icdf_log_logistic(p, .5, .5));
  482. CHECK_RELERR(x*x*2, icdf_log_logistic(p, 2, .5));
  483. if (np < .9) {
  484. CHECK_RELERR(x, isf_log_logistic(np, 1, 1));
  485. CHECK_RELERR(x/2, isf_log_logistic(np, .5, 1));
  486. CHECK_RELERR(x*2, isf_log_logistic(np, 2, 1));
  487. CHECK_RELERR(sqrt(x), isf_log_logistic(np, 1, 2));
  488. CHECK_RELERR(sqrt(x)/2, isf_log_logistic(np, .5, 2));
  489. CHECK_RELERR(sqrt(x)*2, isf_log_logistic(np, 2, 2));
  490. CHECK_RELERR(x*x, isf_log_logistic(np, 1, .5));
  491. CHECK_RELERR(x*x/2, isf_log_logistic(np, .5, .5));
  492. CHECK_RELERR(x*x*2, isf_log_logistic(np, 2, .5));
  493. CHECK_RELERR(1/x, icdf_log_logistic(np, 1, 1));
  494. CHECK_RELERR(1/(2*x), icdf_log_logistic(np, .5, 1));
  495. CHECK_RELERR(2/x, icdf_log_logistic(np, 2, 1));
  496. CHECK_RELERR(1/sqrt(x), icdf_log_logistic(np, 1, 2));
  497. CHECK_RELERR(1/(2*sqrt(x)),
  498. icdf_log_logistic(np, .5, 2));
  499. CHECK_RELERR(2/sqrt(x), icdf_log_logistic(np, 2, 2));
  500. CHECK_RELERR(1/(x*x), icdf_log_logistic(np, 1, .5));
  501. CHECK_RELERR(1/(2*x*x), icdf_log_logistic(np, .5, .5));
  502. CHECK_RELERR(2/(x*x), icdf_log_logistic(np, 2, .5));
  503. }
  504. CHECK_RELERR(1/x, isf_log_logistic(p, 1, 1));
  505. CHECK_RELERR(1/(2*x), isf_log_logistic(p, .5, 1));
  506. CHECK_RELERR(2/x, isf_log_logistic(p, 2, 1));
  507. CHECK_RELERR(1/sqrt(x), isf_log_logistic(p, 1, 2));
  508. CHECK_RELERR(1/(2*sqrt(x)), isf_log_logistic(p, .5, 2));
  509. CHECK_RELERR(2/sqrt(x), isf_log_logistic(p, 2, 2));
  510. CHECK_RELERR(1/(x*x), isf_log_logistic(p, 1, .5));
  511. CHECK_RELERR(1/(2*x*x), isf_log_logistic(p, .5, .5));
  512. CHECK_RELERR(2/(x*x), isf_log_logistic(p, 2, .5));
  513. }
  514. for (i = 0; i <= 100; i++) {
  515. double p0 = (double)i/100;
  516. CHECK_RELERR(0.5*p0/(1 - 0.5*p0), sample_log_logistic(0, p0));
  517. CHECK_RELERR((1 - 0.5*p0)/(0.5*p0),
  518. sample_log_logistic(1, p0));
  519. }
  520. if (!ok)
  521. printf("fail log logistic cdf/sf\n");
  522. tt_assert(ok);
  523. done:
  524. ;
  525. }
  526. /**
  527. * Test the cdf, sf, icdf, isf of the Weibull distribution.
  528. */
  529. static void
  530. test_weibull(void *arg)
  531. {
  532. (void) arg;
  533. static const struct {
  534. /* x is a point in the support of the Weibull distribution */
  535. double x;
  536. /* 'p' is the probability that a random variable X for a given Weibull
  537. * probability ditribution will take value less-or-equal to x */
  538. double p;
  539. /* 'np' is the probability that a random variable X for a given Weibull
  540. * probability distribution will take value greater-or-equal to x. */
  541. double np;
  542. } cases[] = {
  543. { 0, 0, 1 },
  544. { 1e-300, 1e-300, 1 },
  545. { 1e-17, 1e-17, 1 },
  546. { .1, .09516258196404043, .9048374180359595 },
  547. { .5, .3934693402873666, .6065306597126334 },
  548. { .6931471805599453, .5, .5 },
  549. { 1, .6321205588285577, .36787944117144233 },
  550. { 10, .9999546000702375, 4.5399929762484854e-5 },
  551. { 36, .9999999999999998, 2.319522830243569e-16 },
  552. { 37, .9999999999999999, 8.533047625744066e-17 },
  553. { 38, 1, 3.1391327920480296e-17 },
  554. { 100, 1, 3.720075976020836e-44 },
  555. { 708, 1, 3.307553003638408e-308 },
  556. { 710, 1, 4.47628622567513e-309 },
  557. { 1000, 1, 0 },
  558. { HUGE_VAL, 1, 0 },
  559. };
  560. double relerr_bound = 3e-15;
  561. size_t i;
  562. bool ok = true;
  563. for (i = 0; i < arraycount(cases); i++) {
  564. double x = cases[i].x;
  565. double p = cases[i].p;
  566. double np = cases[i].np;
  567. CHECK_RELERR(p, cdf_weibull(x, 1, 1));
  568. CHECK_RELERR(p, cdf_weibull(x/2, .5, 1));
  569. CHECK_RELERR(p, cdf_weibull(x*2, 2, 1));
  570. /* For 0 < x < sqrt(DBL_MIN), x^2 loses lots of bits. */
  571. if (x <= 0 ||
  572. sqrt(DBL_MIN) <= x) {
  573. CHECK_RELERR(p, cdf_weibull(x*x, 1, .5));
  574. CHECK_RELERR(p, cdf_weibull(x*x/2, .5, .5));
  575. CHECK_RELERR(p, cdf_weibull(x*x*2, 2, .5));
  576. }
  577. CHECK_RELERR(p, cdf_weibull(sqrt(x), 1, 2));
  578. CHECK_RELERR(p, cdf_weibull(sqrt(x)/2, .5, 2));
  579. CHECK_RELERR(p, cdf_weibull(sqrt(x)*2, 2, 2));
  580. CHECK_RELERR(np, sf_weibull(x, 1, 1));
  581. CHECK_RELERR(np, sf_weibull(x/2, .5, 1));
  582. CHECK_RELERR(np, sf_weibull(x*2, 2, 1));
  583. CHECK_RELERR(np, sf_weibull(x*x, 1, .5));
  584. CHECK_RELERR(np, sf_weibull(x*x/2, .5, .5));
  585. CHECK_RELERR(np, sf_weibull(x*x*2, 2, .5));
  586. if (x >= 10) {
  587. /*
  588. * exp amplifies the error of sqrt(x)^2
  589. * proportionally to exp(x); for large inputs
  590. * this is significant.
  591. */
  592. double t = -expm1(-x*(2*DBL_EPSILON + DBL_EPSILON));
  593. relerr_bound = t + DBL_EPSILON + t*DBL_EPSILON;
  594. if (relerr_bound < 3e-15)
  595. /*
  596. * The tests are written only to 16
  597. * decimal places anyway even if your
  598. * `double' is, say, i387 binary80, for
  599. * whatever reason.
  600. */
  601. relerr_bound = 3e-15;
  602. CHECK_RELERR(np, sf_weibull(sqrt(x), 1, 2));
  603. CHECK_RELERR(np, sf_weibull(sqrt(x)/2, .5, 2));
  604. CHECK_RELERR(np, sf_weibull(sqrt(x)*2, 2, 2));
  605. }
  606. if (p <= 0.75) {
  607. /*
  608. * For p near 1, not enough precision near 1 to
  609. * recover x.
  610. */
  611. CHECK_RELERR(x, icdf_weibull(p, 1, 1));
  612. CHECK_RELERR(x/2, icdf_weibull(p, .5, 1));
  613. CHECK_RELERR(x*2, icdf_weibull(p, 2, 1));
  614. }
  615. if (p >= 0.25 && !tor_isinf(x) && np > 0) {
  616. /*
  617. * For p near 0, not enough precision in np
  618. * near 1 to recover x. For 0, isf gives inf,
  619. * even if p is precise enough for the icdf to
  620. * work.
  621. */
  622. CHECK_RELERR(x, isf_weibull(np, 1, 1));
  623. CHECK_RELERR(x/2, isf_weibull(np, .5, 1));
  624. CHECK_RELERR(x*2, isf_weibull(np, 2, 1));
  625. }
  626. }
  627. for (i = 0; i <= 100; i++) {
  628. double p0 = (double)i/100;
  629. CHECK_RELERR(3*sqrt(-log(p0/2)), sample_weibull(0, p0, 3, 2));
  630. CHECK_RELERR(3*sqrt(-log1p(-p0/2)),
  631. sample_weibull(1, p0, 3, 2));
  632. }
  633. if (!ok)
  634. printf("fail Weibull cdf/sf\n");
  635. tt_assert(ok);
  636. done:
  637. ;
  638. }
  639. /**
  640. * Test the cdf, sf, icdf, and isf of the generalized Pareto
  641. * distribution.
  642. */
  643. static void
  644. test_genpareto(void *arg)
  645. {
  646. (void) arg;
  647. struct {
  648. /* xi is the 'xi' parameter of the generalized Pareto distribution, and the
  649. * rest are the same as in the above tests */
  650. double xi, x, p, np;
  651. } cases[] = {
  652. { 0, 0, 0, 1 },
  653. { 1e-300, .004, 3.992010656008528e-3, .9960079893439915 },
  654. { 1e-300, .1, .09516258196404043, .9048374180359595 },
  655. { 1e-300, 1, .6321205588285577, .36787944117144233 },
  656. { 1e-300, 10, .9999546000702375, 4.5399929762484854e-5 },
  657. { 1e-200, 1e-16, 9.999999999999999e-17, .9999999999999999 },
  658. { 1e-16, 1e-200, 9.999999999999998e-201, 1 },
  659. { 1e-16, 1e-16, 1e-16, 1 },
  660. { 1e-16, .004, 3.992010656008528e-3, .9960079893439915 },
  661. { 1e-16, .1, .09516258196404043, .9048374180359595 },
  662. { 1e-16, 1, .6321205588285577, .36787944117144233 },
  663. { 1e-16, 10, .9999546000702375, 4.539992976248509e-5 },
  664. { 1e-10, 1e-6, 9.999995000001667e-7, .9999990000005 },
  665. { 1e-8, 1e-8, 9.999999950000001e-9, .9999999900000001 },
  666. { 1, 1e-300, 1e-300, 1 },
  667. { 1, 1e-16, 1e-16, .9999999999999999 },
  668. { 1, .1, .09090909090909091, .9090909090909091 },
  669. { 1, 1, .5, .5 },
  670. { 1, 10, .9090909090909091, .0909090909090909 },
  671. { 1, 100, .9900990099009901, .0099009900990099 },
  672. { 1, 1000, .999000999000999, 9.990009990009992e-4 },
  673. { 10, 1e-300, 1e-300, 1 },
  674. { 10, 1e-16, 9.999999999999995e-17, .9999999999999999 },
  675. { 10, .1, .06696700846319258, .9330329915368074 },
  676. { 10, 1, .21320655780322778, .7867934421967723 },
  677. { 10, 10, .3696701667040189, .6303298332959811 },
  678. { 10, 100, .49886285755007337, .5011371424499267 },
  679. { 10, 1000, .6018968102992647, .3981031897007353 },
  680. };
  681. double xi_array[] = { -1.5, -1, -1e-30, 0, 1e-30, 1, 1.5 };
  682. size_t i, j;
  683. double relerr_bound = 3e-15;
  684. bool ok = true;
  685. for (i = 0; i < arraycount(cases); i++) {
  686. double xi = cases[i].xi;
  687. double x = cases[i].x;
  688. double p = cases[i].p;
  689. double np = cases[i].np;
  690. CHECK_RELERR(p, cdf_genpareto(x, 0, 1, xi));
  691. CHECK_RELERR(p, cdf_genpareto(x*2, 0, 2, xi));
  692. CHECK_RELERR(p, cdf_genpareto(x/2, 0, .5, xi));
  693. CHECK_RELERR(np, sf_genpareto(x, 0, 1, xi));
  694. CHECK_RELERR(np, sf_genpareto(x*2, 0, 2, xi));
  695. CHECK_RELERR(np, sf_genpareto(x/2, 0, .5, xi));
  696. if (p < .5) {
  697. CHECK_RELERR(x, icdf_genpareto(p, 0, 1, xi));
  698. CHECK_RELERR(x*2, icdf_genpareto(p, 0, 2, xi));
  699. CHECK_RELERR(x/2, icdf_genpareto(p, 0, .5, xi));
  700. }
  701. if (np < .5) {
  702. CHECK_RELERR(x, isf_genpareto(np, 0, 1, xi));
  703. CHECK_RELERR(x*2, isf_genpareto(np, 0, 2, xi));
  704. CHECK_RELERR(x/2, isf_genpareto(np, 0, .5, xi));
  705. }
  706. }
  707. for (i = 0; i < arraycount(xi_array); i++) {
  708. for (j = 0; j <= 100; j++) {
  709. double p0 = (j == 0 ? 2*DBL_MIN : (double)j/100);
  710. /* This is actually a check against 0, but we do <= so that the compiler
  711. does not raise a -Wfloat-equal */
  712. if (fabs(xi_array[i]) <= 0) {
  713. /*
  714. * When xi == 0, the generalized Pareto
  715. * distribution reduces to an
  716. * exponential distribution.
  717. */
  718. CHECK_RELERR(-log(p0/2),
  719. sample_genpareto(0, p0, 0));
  720. CHECK_RELERR(-log1p(-p0/2),
  721. sample_genpareto(1, p0, 0));
  722. } else {
  723. CHECK_RELERR(expm1(-xi_array[i]*log(p0/2))/xi_array[i],
  724. sample_genpareto(0, p0, xi_array[i]));
  725. CHECK_RELERR((j == 0 ? DBL_MIN :
  726. expm1(-xi_array[i]*log1p(-p0/2))/xi_array[i]),
  727. sample_genpareto(1, p0, xi_array[i]));
  728. }
  729. CHECK_RELERR(isf_genpareto(p0/2, 0, 1, xi_array[i]),
  730. sample_genpareto(0, p0, xi_array[i]));
  731. CHECK_RELERR(icdf_genpareto(p0/2, 0, 1, xi_array[i]),
  732. sample_genpareto(1, p0, xi_array[i]));
  733. }
  734. }
  735. tt_assert(ok);
  736. done:
  737. ;
  738. }
  739. /**
  740. * Test the deterministic sampler for uniform distribution on [a, b].
  741. *
  742. * This currently only tests whether the outcome lies within [a, b].
  743. */
  744. static void
  745. test_uniform_interval(void *arg)
  746. {
  747. (void) arg;
  748. struct {
  749. /* Sample from a uniform distribution with parameters 'a' and 'b', using
  750. * 't' as the sampling index. */
  751. double t, a, b;
  752. } cases[] = {
  753. { 0, 0, 0 },
  754. { 0, 0, 1 },
  755. { 0, 1.0000000000000007, 3.999999999999995 },
  756. { 0, 4000, 4000 },
  757. { 0.42475836677491291, 4000, 4000 },
  758. { 0, -DBL_MAX, DBL_MAX },
  759. { 0.25, -DBL_MAX, DBL_MAX },
  760. { 0.5, -DBL_MAX, DBL_MAX },
  761. };
  762. size_t i = 0;
  763. bool ok = true;
  764. for (i = 0; i < arraycount(cases); i++) {
  765. double t = cases[i].t;
  766. double a = cases[i].a;
  767. double b = cases[i].b;
  768. CHECK_LE(a, sample_uniform_interval(t, a, b));
  769. CHECK_LE(sample_uniform_interval(t, a, b), b);
  770. CHECK_LE(a, sample_uniform_interval(1 - t, a, b));
  771. CHECK_LE(sample_uniform_interval(1 - t, a, b), b);
  772. CHECK_LE(sample_uniform_interval(t, -b, -a), -a);
  773. CHECK_LE(-b, sample_uniform_interval(t, -b, -a));
  774. CHECK_LE(sample_uniform_interval(1 - t, -b, -a), -a);
  775. CHECK_LE(-b, sample_uniform_interval(1 - t, -b, -a));
  776. }
  777. tt_assert(ok);
  778. done:
  779. ;
  780. }
  781. /********************** Stochastic tests ****************************/
  782. /*
  783. * Psi test, sometimes also called G-test. The psi test statistic,
  784. * suitably scaled, has chi^2 distribution, but the psi test tends to
  785. * have better statistical power in practice to detect deviations than
  786. * the chi^2 test does. (The chi^2 test statistic is the first term of
  787. * the Taylor expansion of the psi test statistic.) The psi test is
  788. * generic, for any CDF; particular distributions might have higher-
  789. * power tests to distinguish them from predictable deviations or bugs.
  790. *
  791. * We choose the psi critical value so that a single psi test has
  792. * probability below alpha = 1% of spuriously failing even if all the
  793. * code is correct. But the false positive rate for a suite of n tests
  794. * is higher: 1 - Binom(0; n, alpha) = 1 - (1 - alpha)^n. For n = 10,
  795. * this is about 10%, and for n = 100 it is well over 50%.
  796. *
  797. * Given that these tests will run with every CI job, we want to drive down the
  798. * false positive rate. We can drive it down by running each test four times,
  799. * and accepting it if it passes at least once; in that case, it is as if we
  800. * used Binom(4; 2, alpha) = alpha^4 as the false positive rate for each test,
  801. * and for n = 10 tests, it would be 9.99999959506e-08. If each CI build has 14
  802. * jobs, then the chance of a CI build failing is 1.39999903326e-06, which
  803. * means that a CI build will break with probability 50% after about 495106
  804. * builds.
  805. *
  806. * The critical value for a chi^2 distribution with 100 degrees of
  807. * freedom and false positive rate alpha = 1% was taken from:
  808. *
  809. * NIST/SEMATECH e-Handbook of Statistical Methods, Section
  810. * 1.3.6.7.4 `Critical Values of the Chi-Square Distribution',
  811. * <http://www.itl.nist.gov/div898/handbook/eda/section3/eda3674.htm>,
  812. * retrieved 2018-10-28.
  813. */
  814. static const size_t NSAMPLES = 100000;
  815. /* Number of chances we give to the test to succeed. */
  816. static const unsigned NTRIALS = 4;
  817. /* Number of times we want the test to pass per NTRIALS. */
  818. static const unsigned NPASSES_MIN = 1;
  819. #define PSI_DF 100 /* degrees of freedom */
  820. static const double PSI_CRITICAL = 135.807; /* critical value, alpha = .01 */
  821. /**
  822. * Perform a psi test on an array of sample counts, C, adding up to N
  823. * samples, and an array of log expected probabilities, logP,
  824. * representing the null hypothesis for the distribution of samples
  825. * counted. Return false if the psi test rejects the null hypothesis,
  826. * true if otherwise.
  827. */
  828. static bool
  829. psi_test(const size_t C[PSI_DF], const double logP[PSI_DF], size_t N)
  830. {
  831. double psi = 0;
  832. double c = 0; /* Kahan compensation */
  833. double t, u;
  834. size_t i;
  835. for (i = 0; i < PSI_DF; i++) {
  836. /*
  837. * c*log(c/(n*p)) = (1/n) * f*log(f/p) where f = c/n is
  838. * the frequency, and f*log(f/p) ---> 0 as f ---> 0, so
  839. * this is a reasonable choice. Further, any mass that
  840. * _fails_ to turn up in this bin will inflate another
  841. * bin instead, so we don't really lose anything by
  842. * ignoring empty bins even if they have high
  843. * probability.
  844. */
  845. if (C[i] == 0)
  846. continue;
  847. t = C[i]*(log((double)C[i]/N) - logP[i]) - c;
  848. u = psi + t;
  849. c = (u - psi) - t;
  850. psi = u;
  851. }
  852. psi *= 2;
  853. return psi <= PSI_CRITICAL;
  854. }
  855. static bool
  856. test_stochastic_geometric_impl(double p)
  857. {
  858. const struct geometric geometric = {
  859. .base = GEOMETRIC(geometric),
  860. .p = p,
  861. };
  862. double logP[PSI_DF] = {0};
  863. unsigned ntry = NTRIALS, npass = 0;
  864. unsigned i;
  865. size_t j;
  866. /* Compute logP[i] = Geom(i + 1; p). */
  867. for (i = 0; i < PSI_DF - 1; i++)
  868. logP[i] = logpmf_geometric(i + 1, p);
  869. /* Compute logP[n-1] = log (1 - (P[0] + P[1] + ... + P[n-2])). */
  870. logP[PSI_DF - 1] = log1mexp(logsumexp(logP, PSI_DF - 1));
  871. while (ntry --> 0) {
  872. size_t C[PSI_DF] = {0};
  873. for (j = 0; j < NSAMPLES; j++) {
  874. double n_tmp = dist_sample(&geometric.base);
  875. /* Must be an integer. (XXX -Wfloat-equal) */
  876. tor_assert(ceil(n_tmp) <= n_tmp && ceil(n_tmp) >= n_tmp);
  877. /* Must be a positive integer. */
  878. tor_assert(n_tmp >= 1);
  879. /* Probability of getting a value in the billions is negligible. */
  880. tor_assert(n_tmp <= (double)UINT_MAX);
  881. unsigned n = (unsigned) n_tmp;
  882. if (n > PSI_DF)
  883. n = PSI_DF;
  884. C[n - 1]++;
  885. }
  886. if (psi_test(C, logP, NSAMPLES)) {
  887. if (++npass >= NPASSES_MIN)
  888. break;
  889. }
  890. }
  891. if (npass >= NPASSES_MIN) {
  892. /* printf("pass %s sampler\n", "geometric"); */
  893. return true;
  894. } else {
  895. printf("fail %s sampler\n", "geometric");
  896. return false;
  897. }
  898. }
  899. /**
  900. * Divide the support of <b>dist</b> into histogram bins in <b>logP</b>. Start
  901. * at the 1st percentile and ending at the 99th percentile. Pick the bin
  902. * boundaries using linear interpolation so that they are uniformly spaced.
  903. *
  904. * In each bin logP[i] we insert the expected log-probability that a sampled
  905. * value will fall into that bin. We will use this as the null hypothesis of
  906. * the psi test.
  907. *
  908. * Set logP[i] = log(CDF(x_i) - CDF(x_{i-1})), where x_-1 = -inf, x_n =
  909. * +inf, and x_i = i*(hi - lo)/(n - 2).
  910. */
  911. static void
  912. bin_cdfs(const struct dist *dist, double lo, double hi, double *logP, size_t n)
  913. {
  914. #define CDF(x) dist_cdf(dist, x)
  915. #define SF(x) dist_sf(dist, x)
  916. const double w = (hi - lo)/(n - 2);
  917. double halfway = dist_icdf(dist, 0.5);
  918. double x_0, x_1;
  919. size_t i;
  920. size_t n2 = ceil_to_size_t((halfway - lo)/w);
  921. tor_assert(lo <= halfway);
  922. tor_assert(halfway <= hi);
  923. tor_assert(n2 <= n);
  924. x_1 = lo;
  925. logP[0] = log(CDF(x_1) - 0); /* 0 = CDF(-inf) */
  926. for (i = 1; i < n2; i++) {
  927. x_0 = x_1;
  928. /* do the linear interpolation */
  929. x_1 = (i <= n/2 ? lo + i*w : hi - (n - 2 - i)*w);
  930. /* set the expected log-probability */
  931. logP[i] = log(CDF(x_1) - CDF(x_0));
  932. }
  933. x_0 = hi;
  934. logP[n - 1] = log(SF(x_0) - 0); /* 0 = SF(+inf) = 1 - CDF(+inf) */
  935. /* In this loop we are filling out the high part of the array. We are using
  936. * SF because in these cases the CDF is near 1 where precision is lower. So
  937. * instead we are using SF near 0 where the precision is higher. We have
  938. * SF(t) = 1 - CDF(t). */
  939. for (i = 1; i < n - n2; i++) {
  940. x_1 = x_0;
  941. /* do the linear interpolation */
  942. x_0 = (i <= n/2 ? hi - i*w : lo + (n - 2 - i)*w);
  943. /* set the expected log-probability */
  944. logP[n - i - 1] = log(SF(x_0) - SF(x_1));
  945. }
  946. #undef SF
  947. #undef CDF
  948. }
  949. /**
  950. * Draw NSAMPLES samples from dist, counting the number of samples x in
  951. * the ith bin C[i] if x_{i-1} <= x < x_i, where x_-1 = -inf, x_n =
  952. * +inf, and x_i = i*(hi - lo)/(n - 2).
  953. */
  954. static void
  955. bin_samples(const struct dist *dist, double lo, double hi, size_t *C, size_t n)
  956. {
  957. const double w = (hi - lo)/(n - 2);
  958. size_t i;
  959. for (i = 0; i < NSAMPLES; i++) {
  960. double x = dist_sample(dist);
  961. size_t bin;
  962. if (x < lo)
  963. bin = 0;
  964. else if (x < hi)
  965. bin = 1 + floor_to_size_t((x - lo)/w);
  966. else
  967. bin = n - 1;
  968. tor_assert(bin < n);
  969. C[bin]++;
  970. }
  971. }
  972. /**
  973. * Carry out a Psi test on <b>dist</b>.
  974. *
  975. * Sample NSAMPLES from dist, putting them in bins from -inf to lo to
  976. * hi to +inf, and apply up to two psi tests. True if at least one psi
  977. * test passes; false if not. False positive rate should be bounded by
  978. * 0.01^2 = 0.0001.
  979. */
  980. static bool
  981. test_psi_dist_sample(const struct dist *dist)
  982. {
  983. double logP[PSI_DF] = {0};
  984. unsigned ntry = NTRIALS, npass = 0;
  985. double lo = dist_icdf(dist, 1/(double)(PSI_DF + 2));
  986. double hi = dist_isf(dist, 1/(double)(PSI_DF + 2));
  987. /* Create the null hypothesis in logP */
  988. bin_cdfs(dist, lo, hi, logP, PSI_DF);
  989. /* Now run the test */
  990. while (ntry --> 0) {
  991. size_t C[PSI_DF] = {0};
  992. bin_samples(dist, lo, hi, C, PSI_DF);
  993. if (psi_test(C, logP, NSAMPLES)) {
  994. if (++npass >= NPASSES_MIN)
  995. break;
  996. }
  997. }
  998. /* Did we fail or succeed? */
  999. if (npass >= NPASSES_MIN) {
  1000. /* printf("pass %s sampler\n", dist_name(dist));*/
  1001. return true;
  1002. } else {
  1003. printf("fail %s sampler\n", dist_name(dist));
  1004. return false;
  1005. }
  1006. }
  1007. static void
  1008. write_stochastic_warning(void)
  1009. {
  1010. if (tinytest_cur_test_has_failed()) {
  1011. printf("\n"
  1012. "NOTE: This is a stochastic test, and we expect it to fail from\n"
  1013. "time to time, with some low probability. If you see it fail more\n"
  1014. "than one trial in 100, though, please tell us.\n\n");
  1015. }
  1016. }
  1017. static void
  1018. test_stochastic_uniform(void *arg)
  1019. {
  1020. (void) arg;
  1021. const struct uniform uniform01 = {
  1022. .base = UNIFORM(uniform01),
  1023. .a = 0,
  1024. .b = 1,
  1025. };
  1026. const struct uniform uniform_pos = {
  1027. .base = UNIFORM(uniform_pos),
  1028. .a = 1.23,
  1029. .b = 4.56,
  1030. };
  1031. const struct uniform uniform_neg = {
  1032. .base = UNIFORM(uniform_neg),
  1033. .a = -10,
  1034. .b = -1,
  1035. };
  1036. const struct uniform uniform_cross = {
  1037. .base = UNIFORM(uniform_cross),
  1038. .a = -1.23,
  1039. .b = 4.56,
  1040. };
  1041. const struct uniform uniform_subnormal = {
  1042. .base = UNIFORM(uniform_subnormal),
  1043. .a = 4e-324,
  1044. .b = 4e-310,
  1045. };
  1046. const struct uniform uniform_subnormal_cross = {
  1047. .base = UNIFORM(uniform_subnormal_cross),
  1048. .a = -4e-324,
  1049. .b = 4e-310,
  1050. };
  1051. bool ok = true, tests_failed = true;
  1052. testing_enable_reproducible_rng();
  1053. ok &= test_psi_dist_sample(&uniform01.base);
  1054. ok &= test_psi_dist_sample(&uniform_pos.base);
  1055. ok &= test_psi_dist_sample(&uniform_neg.base);
  1056. ok &= test_psi_dist_sample(&uniform_cross.base);
  1057. ok &= test_psi_dist_sample(&uniform_subnormal.base);
  1058. ok &= test_psi_dist_sample(&uniform_subnormal_cross.base);
  1059. tt_assert(ok);
  1060. tests_failed = false;
  1061. done:
  1062. if (tests_failed) {
  1063. write_stochastic_warning();
  1064. }
  1065. testing_disable_reproducible_rng();
  1066. }
  1067. static bool
  1068. test_stochastic_logistic_impl(double mu, double sigma)
  1069. {
  1070. const struct logistic dist = {
  1071. .base = LOGISTIC(dist),
  1072. .mu = mu,
  1073. .sigma = sigma,
  1074. };
  1075. /* XXX Consider some fancier logistic test. */
  1076. return test_psi_dist_sample(&dist.base);
  1077. }
  1078. static bool
  1079. test_stochastic_log_logistic_impl(double alpha, double beta)
  1080. {
  1081. const struct log_logistic dist = {
  1082. .base = LOG_LOGISTIC(dist),
  1083. .alpha = alpha,
  1084. .beta = beta,
  1085. };
  1086. /* XXX Consider some fancier log logistic test. */
  1087. return test_psi_dist_sample(&dist.base);
  1088. }
  1089. static bool
  1090. test_stochastic_weibull_impl(double lambda, double k)
  1091. {
  1092. const struct weibull dist = {
  1093. .base = WEIBULL(dist),
  1094. .lambda = lambda,
  1095. .k = k,
  1096. };
  1097. /*
  1098. * XXX Consider applying a Tiku-Singh test:
  1099. *
  1100. * M.L. Tiku and M. Singh, `Testing the two-parameter
  1101. * Weibull distribution', Communications in Statistics --
  1102. * Theory and Methods A10(9), 1981, 907--918.
  1103. *https://www.tandfonline.com/doi/pdf/10.1080/03610928108828082?needAccess=true
  1104. */
  1105. return test_psi_dist_sample(&dist.base);
  1106. }
  1107. static bool
  1108. test_stochastic_genpareto_impl(double mu, double sigma, double xi)
  1109. {
  1110. const struct genpareto dist = {
  1111. .base = GENPARETO(dist),
  1112. .mu = mu,
  1113. .sigma = sigma,
  1114. .xi = xi,
  1115. };
  1116. /* XXX Consider some fancier GPD test. */
  1117. return test_psi_dist_sample(&dist.base);
  1118. }
  1119. static void
  1120. test_stochastic_genpareto(void *arg)
  1121. {
  1122. bool ok = 0;
  1123. bool tests_failed = true;
  1124. (void) arg;
  1125. testing_enable_reproducible_rng();
  1126. ok = test_stochastic_genpareto_impl(0, 1, -0.25);
  1127. tt_assert(ok);
  1128. ok = test_stochastic_genpareto_impl(0, 1, -1e-30);
  1129. tt_assert(ok);
  1130. ok = test_stochastic_genpareto_impl(0, 1, 0);
  1131. tt_assert(ok);
  1132. ok = test_stochastic_genpareto_impl(0, 1, 1e-30);
  1133. tt_assert(ok);
  1134. ok = test_stochastic_genpareto_impl(0, 1, 0.25);
  1135. tt_assert(ok);
  1136. ok = test_stochastic_genpareto_impl(-1, 1, -0.25);
  1137. tt_assert(ok);
  1138. ok = test_stochastic_genpareto_impl(1, 2, 0.25);
  1139. tt_assert(ok);
  1140. tests_failed = false;
  1141. done:
  1142. if (tests_failed) {
  1143. write_stochastic_warning();
  1144. }
  1145. testing_disable_reproducible_rng();
  1146. }
  1147. static void
  1148. test_stochastic_geometric(void *arg)
  1149. {
  1150. bool ok = 0;
  1151. bool tests_failed = true;
  1152. (void) arg;
  1153. testing_enable_reproducible_rng();
  1154. ok = test_stochastic_geometric_impl(0.1);
  1155. tt_assert(ok);
  1156. ok = test_stochastic_geometric_impl(0.5);
  1157. tt_assert(ok);
  1158. ok = test_stochastic_geometric_impl(0.9);
  1159. tt_assert(ok);
  1160. ok = test_stochastic_geometric_impl(1);
  1161. tt_assert(ok);
  1162. tests_failed = false;
  1163. done:
  1164. if (tests_failed) {
  1165. write_stochastic_warning();
  1166. }
  1167. testing_disable_reproducible_rng();
  1168. }
  1169. static void
  1170. test_stochastic_logistic(void *arg)
  1171. {
  1172. bool ok = 0;
  1173. bool tests_failed = true;
  1174. (void) arg;
  1175. testing_enable_reproducible_rng();
  1176. ok = test_stochastic_logistic_impl(0, 1);
  1177. tt_assert(ok);
  1178. ok = test_stochastic_logistic_impl(0, 1e-16);
  1179. tt_assert(ok);
  1180. ok = test_stochastic_logistic_impl(1, 10);
  1181. tt_assert(ok);
  1182. ok = test_stochastic_logistic_impl(-10, 100);
  1183. tt_assert(ok);
  1184. tests_failed = false;
  1185. done:
  1186. if (tests_failed) {
  1187. write_stochastic_warning();
  1188. }
  1189. testing_disable_reproducible_rng();
  1190. }
  1191. static void
  1192. test_stochastic_log_logistic(void *arg)
  1193. {
  1194. bool ok = 0;
  1195. (void) arg;
  1196. testing_enable_reproducible_rng();
  1197. ok = test_stochastic_log_logistic_impl(1, 1);
  1198. tt_assert(ok);
  1199. ok = test_stochastic_log_logistic_impl(1, 10);
  1200. tt_assert(ok);
  1201. ok = test_stochastic_log_logistic_impl(M_E, 1e-1);
  1202. tt_assert(ok);
  1203. ok = test_stochastic_log_logistic_impl(exp(-10), 1e-2);
  1204. tt_assert(ok);
  1205. done:
  1206. write_stochastic_warning();
  1207. testing_disable_reproducible_rng();
  1208. }
  1209. static void
  1210. test_stochastic_weibull(void *arg)
  1211. {
  1212. bool ok = 0;
  1213. (void) arg;
  1214. testing_enable_reproducible_rng();
  1215. ok = test_stochastic_weibull_impl(1, 0.5);
  1216. tt_assert(ok);
  1217. ok = test_stochastic_weibull_impl(1, 1);
  1218. tt_assert(ok);
  1219. ok = test_stochastic_weibull_impl(1, 1.5);
  1220. tt_assert(ok);
  1221. ok = test_stochastic_weibull_impl(1, 2);
  1222. tt_assert(ok);
  1223. ok = test_stochastic_weibull_impl(10, 1);
  1224. tt_assert(ok);
  1225. done:
  1226. write_stochastic_warning();
  1227. testing_disable_reproducible_rng();
  1228. UNMOCK(crypto_rand);
  1229. }
  1230. struct testcase_t prob_distr_tests[] = {
  1231. { "logit_logistics", test_logit_logistic, TT_FORK, NULL, NULL },
  1232. { "log_logistic", test_log_logistic, TT_FORK, NULL, NULL },
  1233. { "weibull", test_weibull, TT_FORK, NULL, NULL },
  1234. { "genpareto", test_genpareto, TT_FORK, NULL, NULL },
  1235. { "uniform_interval", test_uniform_interval, TT_FORK, NULL, NULL },
  1236. END_OF_TESTCASES
  1237. };
  1238. struct testcase_t slow_stochastic_prob_distr_tests[] = {
  1239. { "stochastic_genpareto", test_stochastic_genpareto, TT_FORK, NULL, NULL },
  1240. { "stochastic_geometric", test_stochastic_geometric, TT_FORK, NULL, NULL },
  1241. { "stochastic_uniform", test_stochastic_uniform, TT_FORK, NULL, NULL },
  1242. { "stochastic_logistic", test_stochastic_logistic, TT_FORK, NULL, NULL },
  1243. { "stochastic_log_logistic", test_stochastic_log_logistic, TT_FORK, NULL,
  1244. NULL },
  1245. { "stochastic_weibull", test_stochastic_weibull, TT_FORK, NULL, NULL },
  1246. END_OF_TESTCASES
  1247. };