Loading src/core/or/circuitpadding.c +10 −6 Original line number Diff line number Diff line Loading @@ -545,7 +545,7 @@ circpad_distribution_sample(circpad_distribution_t dist) .a = dist.param1, .b = dist.param2, }; return uniform_sample(&my_uniform.base); return dist_sample(&my_uniform.base); } case CIRCPAD_DIST_LOGISTIC: { Loading @@ -555,7 +555,7 @@ circpad_distribution_sample(circpad_distribution_t dist) .mu = dist.param1, .sigma = dist.param2, }; return logistic_sample(&my_logistic.base); return dist_sample(&my_logistic.base); } case CIRCPAD_DIST_LOG_LOGISTIC: { Loading @@ -565,12 +565,16 @@ circpad_distribution_sample(circpad_distribution_t dist) .alpha = dist.param1, .beta = dist.param2, }; return log_logistic_sample(&my_log_logistic.base); return dist_sample(&my_log_logistic.base); } case CIRCPAD_DIST_GEOMETRIC: { /* param1 is 'p' (success probability) */ return geometric_sample(dist.param1); const struct geometric my_geometric = { .base = DIST_BASE(&geometric_ops), .p = dist.param1, }; return dist_sample(&my_geometric.base); } case CIRCPAD_DIST_WEIBULL: { Loading @@ -580,7 +584,7 @@ circpad_distribution_sample(circpad_distribution_t dist) .k = dist.param1, .lambda = dist.param2, }; return weibull_sample(&my_weibull.base); return dist_sample(&my_weibull.base); } case CIRCPAD_DIST_PARETO: { Loading @@ -591,7 +595,7 @@ circpad_distribution_sample(circpad_distribution_t dist) .sigma = dist.param1, .xi = dist.param2, }; return genpareto_sample(&my_genpareto.base); return dist_sample(&my_genpareto.base); } } Loading src/lib/math/prob_distr.c +159 −70 Original line number Diff line number Diff line Loading @@ -1319,17 +1319,45 @@ sample_geometric(uint32_t s, double p0, double p) * (sample/cdf/sf/icdf/isf) as part of its dist_ops structure. */ /** Functions for uniform distribution */ const struct dist_ops uniform_ops = { .name = "uniform", .sample = uniform_sample, .cdf = uniform_cdf, .sf = uniform_sf, .icdf = uniform_icdf, .isf = uniform_isf, }; const char * dist_name(const struct dist *dist) { return dist->ops->name; } double dist_sample(const struct dist *dist) { return dist->ops->sample(dist); } double dist_cdf(const struct dist *dist, double x) { return dist->ops->cdf(dist, x); } double dist_sf(const struct dist *dist, double x) { return dist->ops->sf(dist, x); } double dist_icdf(const struct dist *dist, double p) { return dist->ops->icdf(dist, p); } double dist_isf(const struct dist *dist, double p) { return dist->ops->isf(dist, p); } /** Functions for uniform distribution */ static double uniform_sample(const struct dist *dist) { const struct uniform *U = const_container_of(dist, struct uniform, Loading @@ -1339,7 +1367,7 @@ uniform_sample(const struct dist *dist) return sample_uniform_interval(p0, U->a, U->b); } double static double uniform_cdf(const struct dist *dist, double x) { const struct uniform *U = const_container_of(dist, struct uniform, Loading @@ -1353,7 +1381,7 @@ uniform_cdf(const struct dist *dist, double x) return 1; } double static double uniform_sf(const struct dist *dist, double x) { const struct uniform *U = const_container_of(dist, struct uniform, Loading @@ -1367,7 +1395,7 @@ uniform_sf(const struct dist *dist, double x) return 1; } double static double uniform_icdf(const struct dist *dist, double p) { const struct uniform *U = const_container_of(dist, struct uniform, Loading @@ -1377,7 +1405,7 @@ uniform_icdf(const struct dist *dist, double p) return (p < 0.5 ? (U->a + w*p) : (U->b - w*(1 - p))); } double static double uniform_isf(const struct dist *dist, double p) { const struct uniform *U = const_container_of(dist, struct uniform, Loading @@ -1387,17 +1415,18 @@ uniform_isf(const struct dist *dist, double p) return (p < 0.5 ? (U->b - w*p) : (U->a + w*(1 - p))); } /** Functions for logistic distribution: */ const struct dist_ops logistic_ops = { .name = "logistic", .sample = logistic_sample, .cdf = logistic_cdf, .sf = logistic_sf, .icdf = logistic_icdf, .isf = logistic_isf, const struct dist_ops uniform_ops = { .name = "uniform", .sample = uniform_sample, .cdf = uniform_cdf, .sf = uniform_sf, .icdf = uniform_icdf, .isf = uniform_isf, }; double /** Functions for logistic distribution: */ static double logistic_sample(const struct dist *dist) { const struct logistic *L = const_container_of(dist, struct logistic, Loading @@ -1409,7 +1438,7 @@ logistic_sample(const struct dist *dist) return sample_logistic_locscale(s, t, p0, L->mu, L->sigma); } double static double logistic_cdf(const struct dist *dist, double x) { const struct logistic *L = const_container_of(dist, struct logistic, Loading @@ -1418,7 +1447,7 @@ logistic_cdf(const struct dist *dist, double x) return cdf_logistic(x, L->mu, L->sigma); } double static double logistic_sf(const struct dist *dist, double x) { const struct logistic *L = const_container_of(dist, struct logistic, Loading @@ -1427,7 +1456,7 @@ logistic_sf(const struct dist *dist, double x) return sf_logistic(x, L->mu, L->sigma); } double static double logistic_icdf(const struct dist *dist, double p) { const struct logistic *L = const_container_of(dist, struct logistic, Loading @@ -1436,7 +1465,7 @@ logistic_icdf(const struct dist *dist, double p) return icdf_logistic(p, L->mu, L->sigma); } double static double logistic_isf(const struct dist *dist, double p) { const struct logistic *L = const_container_of(dist, struct logistic, Loading @@ -1445,17 +1474,18 @@ logistic_isf(const struct dist *dist, double p) return isf_logistic(p, L->mu, L->sigma); } /** Functions for log-logistic distribution: */ const struct dist_ops log_logistic_ops = { .name = "log logistic", .sample = log_logistic_sample, .cdf = log_logistic_cdf, .sf = log_logistic_sf, .icdf = log_logistic_icdf, .isf = log_logistic_isf, const struct dist_ops logistic_ops = { .name = "logistic", .sample = logistic_sample, .cdf = logistic_cdf, .sf = logistic_sf, .icdf = logistic_icdf, .isf = logistic_isf, }; double /** Functions for log-logistic distribution: */ static double log_logistic_sample(const struct dist *dist) { const struct log_logistic *LL = const_container_of(dist, struct Loading @@ -1466,7 +1496,7 @@ log_logistic_sample(const struct dist *dist) return sample_log_logistic_scaleshape(s, p0, LL->alpha, LL->beta); } double static double log_logistic_cdf(const struct dist *dist, double x) { const struct log_logistic *LL = const_container_of(dist, Loading @@ -1475,7 +1505,7 @@ log_logistic_cdf(const struct dist *dist, double x) return cdf_log_logistic(x, LL->alpha, LL->beta); } double static double log_logistic_sf(const struct dist *dist, double x) { const struct log_logistic *LL = const_container_of(dist, Loading @@ -1484,7 +1514,7 @@ log_logistic_sf(const struct dist *dist, double x) return sf_log_logistic(x, LL->alpha, LL->beta); } double static double log_logistic_icdf(const struct dist *dist, double p) { const struct log_logistic *LL = const_container_of(dist, Loading @@ -1493,7 +1523,7 @@ log_logistic_icdf(const struct dist *dist, double p) return icdf_log_logistic(p, LL->alpha, LL->beta); } double static double log_logistic_isf(const struct dist *dist, double p) { const struct log_logistic *LL = const_container_of(dist, Loading @@ -1502,17 +1532,18 @@ log_logistic_isf(const struct dist *dist, double p) return isf_log_logistic(p, LL->alpha, LL->beta); } /** Functions for Weibull distribution */ const struct dist_ops weibull_ops = { .name = "Weibull", .sample = weibull_sample, .cdf = weibull_cdf, .sf = weibull_sf, .icdf = weibull_icdf, .isf = weibull_isf, const struct dist_ops log_logistic_ops = { .name = "log logistic", .sample = log_logistic_sample, .cdf = log_logistic_cdf, .sf = log_logistic_sf, .icdf = log_logistic_icdf, .isf = log_logistic_isf, }; double /** Functions for Weibull distribution */ static double weibull_sample(const struct dist *dist) { const struct weibull *W = const_container_of(dist, struct weibull, Loading @@ -1523,7 +1554,7 @@ weibull_sample(const struct dist *dist) return sample_weibull(s, p0, W->lambda, W->k); } double static double weibull_cdf(const struct dist *dist, double x) { const struct weibull *W = const_container_of(dist, struct weibull, Loading @@ -1532,7 +1563,7 @@ weibull_cdf(const struct dist *dist, double x) return cdf_weibull(x, W->lambda, W->k); } double static double weibull_sf(const struct dist *dist, double x) { const struct weibull *W = const_container_of(dist, struct weibull, Loading @@ -1541,7 +1572,7 @@ weibull_sf(const struct dist *dist, double x) return sf_weibull(x, W->lambda, W->k); } double static double weibull_icdf(const struct dist *dist, double p) { const struct weibull *W = const_container_of(dist, struct weibull, Loading @@ -1550,7 +1581,7 @@ weibull_icdf(const struct dist *dist, double p) return icdf_weibull(p, W->lambda, W->k); } double static double weibull_isf(const struct dist *dist, double p) { const struct weibull *W = const_container_of(dist, struct weibull, Loading @@ -1559,17 +1590,18 @@ weibull_isf(const struct dist *dist, double p) return isf_weibull(p, W->lambda, W->k); } /** Functions for generalized Pareto distributions */ const struct dist_ops genpareto_ops = { .name = "generalized Pareto", .sample = genpareto_sample, .cdf = genpareto_cdf, .sf = genpareto_sf, .icdf = genpareto_icdf, .isf = genpareto_isf, const struct dist_ops weibull_ops = { .name = "Weibull", .sample = weibull_sample, .cdf = weibull_cdf, .sf = weibull_sf, .icdf = weibull_icdf, .isf = weibull_isf, }; double /** Functions for generalized Pareto distributions */ static double genpareto_sample(const struct dist *dist) { const struct genpareto *GP = const_container_of(dist, struct genpareto, Loading @@ -1580,7 +1612,7 @@ genpareto_sample(const struct dist *dist) return sample_genpareto_locscale(s, p0, GP->mu, GP->sigma, GP->xi); } double static double genpareto_cdf(const struct dist *dist, double x) { const struct genpareto *GP = const_container_of(dist, struct genpareto, Loading @@ -1589,7 +1621,7 @@ genpareto_cdf(const struct dist *dist, double x) return cdf_genpareto(x, GP->mu, GP->sigma, GP->xi); } double static double genpareto_sf(const struct dist *dist, double x) { const struct genpareto *GP = const_container_of(dist, struct genpareto, Loading @@ -1598,7 +1630,7 @@ genpareto_sf(const struct dist *dist, double x) return sf_genpareto(x, GP->mu, GP->sigma, GP->xi); } double static double genpareto_icdf(const struct dist *dist, double p) { const struct genpareto *GP = const_container_of(dist, struct genpareto, Loading @@ -1607,7 +1639,7 @@ genpareto_icdf(const struct dist *dist, double p) return icdf_genpareto(p, GP->mu, GP->sigma, GP->xi); } double static double genpareto_isf(const struct dist *dist, double p) { const struct genpareto *GP = const_container_of(dist, struct genpareto, Loading @@ -1616,13 +1648,70 @@ genpareto_isf(const struct dist *dist, double p) return isf_genpareto(p, GP->mu, GP->sigma, GP->xi); } /* Deterministically sample from the geometric distribution with * per-trial success probability p. */ double geometric_sample(double p) const struct dist_ops genpareto_ops = { .name = "generalized Pareto", .sample = genpareto_sample, .cdf = genpareto_cdf, .sf = genpareto_sf, .icdf = genpareto_icdf, .isf = genpareto_isf, }; /** Functions for geometric distribution on number of trials before success */ static double geometric_sample(const struct dist *dist) { const struct geometric *G = const_container_of(dist, struct geometric, base); uint32_t s = crypto_rand_u32(); double p0 = random_uniform_01(); return sample_geometric(s, p0, p); return sample_geometric(s, p0, G->p); } static double geometric_cdf(const struct dist *dist, double x) { const struct geometric *G = const_container_of(dist, struct geometric, base); if (x < 1) return 0; /* 1 - (1 - p)^floor(x) = 1 - e^{floor(x) log(1 - p)} */ return -expm1(floor(x)*log1p(-G->p)); } static double geometric_sf(const struct dist *dist, double x) { const struct geometric *G = const_container_of(dist, struct geometric, base); if (x < 1) return 0; /* (1 - p)^floor(x) = e^{ceil(x) log(1 - p)} */ return exp(floor(x)*log1p(-G->p)); } static double geometric_icdf(const struct dist *dist, double p) { const struct geometric *G = const_container_of(dist, struct geometric, base); return log1p(-p)/log1p(-G->p); } static double geometric_isf(const struct dist *dist, double p) { const struct geometric *G = const_container_of(dist, struct geometric, base); return log(p)/log1p(-G->p); } const struct dist_ops geometric_ops = { .name = "geometric (1-based)", .sample = geometric_sample, .cdf = geometric_cdf, .sf = geometric_sf, .icdf = geometric_icdf, .isf = geometric_isf, }; src/lib/math/prob_distr.h +14 −32 Original line number Diff line number Diff line Loading @@ -21,6 +21,13 @@ struct dist { #define DIST_BASE(OPS) { .ops = (OPS) } const char *dist_name(const struct dist *); double dist_sample(const struct dist *); double dist_cdf(const struct dist *, double x); double dist_sf(const struct dist *, double x); double dist_icdf(const struct dist *, double p); double dist_isf(const struct dist *, double p); struct dist_ops { const char *name; double (*sample)(const struct dist *); Loading @@ -30,9 +37,14 @@ struct dist_ops { double (*isf)(const struct dist *, double p); }; /* Geometric distribution */ /* Geometric distribution on positive number of trials before first success */ double geometric_sample(double p); struct geometric { struct dist base; double p; /* success probability */ }; extern const struct dist_ops geometric_ops; /* Pareto distribution */ Loading @@ -43,12 +55,6 @@ struct genpareto { double xi; }; double genpareto_sample(const struct dist *dist); double genpareto_cdf(const struct dist *dist, double x); double genpareto_sf(const struct dist *dist, double x); double genpareto_icdf(const struct dist *dist, double p); double genpareto_isf(const struct dist *dist, double p); extern const struct dist_ops genpareto_ops; /* Weibull distribution */ Loading @@ -59,12 +65,6 @@ struct weibull { double k; }; double weibull_sample(const struct dist *dist); double weibull_cdf(const struct dist *dist, double x); double weibull_sf(const struct dist *dist, double x); double weibull_icdf(const struct dist *dist, double p); double weibull_isf(const struct dist *dist, double p); extern const struct dist_ops weibull_ops; /* Log-logistic distribution */ Loading @@ -75,12 +75,6 @@ struct log_logistic { double beta; }; double log_logistic_sample(const struct dist *dist); double log_logistic_cdf(const struct dist *dist, double x); double log_logistic_sf(const struct dist *dist, double x); double log_logistic_icdf(const struct dist *dist, double p); double log_logistic_isf(const struct dist *dist, double p); extern const struct dist_ops log_logistic_ops; /* Logistic distribution */ Loading @@ -91,12 +85,6 @@ struct logistic { double sigma; }; double logistic_sample(const struct dist *dist); double logistic_cdf(const struct dist *dist, double x); double logistic_sf(const struct dist *dist, double x); double logistic_icdf(const struct dist *dist, double p); double logistic_isf(const struct dist *dist, double p); extern const struct dist_ops logistic_ops; /* Uniform distribution */ Loading @@ -107,12 +95,6 @@ struct uniform { double b; }; double uniform_sample(const struct dist *dist); double uniform_cdf(const struct dist *dist, double x); double uniform_sf(const struct dist *dist, double x); double uniform_icdf(const struct dist *dist, double p); double uniform_isf(const struct dist *dist, double p); extern const struct dist_ops uniform_ops; /** Only by unittests */ Loading src/test/test_prob_distr.c +13 −9 Original line number Diff line number Diff line Loading @@ -942,6 +942,10 @@ psi_test(const size_t C[PSI_DF], const double logP[PSI_DF], size_t N) static bool test_stochastic_geometric_impl(double p) { const struct geometric geometric = { .base = DIST_BASE(&geometric_ops), .p = p, }; double logP[PSI_DF] = {0}; unsigned ntry = NTRIALS, npass = 0; unsigned i; Loading @@ -958,7 +962,7 @@ test_stochastic_geometric_impl(double p) size_t C[PSI_DF] = {0}; for (j = 0; j < NSAMPLES; j++) { double n_tmp = geometric_sample(p); double n_tmp = dist_sample(&geometric.base); /* Must be an integer. (XXX -Wfloat-equal) */ tor_assert(ceil(n_tmp) <= n_tmp && ceil(n_tmp) >= n_tmp); Loading Loading @@ -1006,10 +1010,10 @@ test_stochastic_geometric_impl(double p) static void bin_cdfs(const struct dist *dist, double lo, double hi, double *logP, size_t n) { #define CDF(x) dist->ops->cdf(dist, x) #define SF(x) dist->ops->sf(dist, x) #define CDF(x) dist_cdf(dist, x) #define SF(x) dist_sf(dist, x) const double w = (hi - lo)/(n - 2); double halfway = dist->ops->icdf(dist, 0.5); double halfway = dist_icdf(dist, 0.5); double x_0, x_1; size_t i; size_t n2 = ceil_to_size_t((halfway - lo)/w); Loading Loading @@ -1057,7 +1061,7 @@ bin_samples(const struct dist *dist, double lo, double hi, size_t *C, size_t n) size_t i; for (i = 0; i < NSAMPLES; i++) { double x = dist->ops->sample(dist); double x = dist_sample(dist); size_t bin; if (x < lo) Loading @@ -1084,8 +1088,8 @@ test_psi_dist_sample(const struct dist *dist) { double logP[PSI_DF] = {0}; unsigned ntry = NTRIALS, npass = 0; double lo = dist->ops->icdf(dist, 1/(double)(PSI_DF + 2)); double hi = dist->ops->isf(dist, 1/(double)(PSI_DF + 2)); double lo = dist_icdf(dist, 1/(double)(PSI_DF + 2)); double hi = dist_isf(dist, 1/(double)(PSI_DF + 2)); /* Create the null hypothesis in logP */ bin_cdfs(dist, lo, hi, logP, PSI_DF); Loading @@ -1102,10 +1106,10 @@ test_psi_dist_sample(const struct dist *dist) /* Did we fail or succeed? */ if (npass >= NPASSES_MIN) { /* printf("pass %s sampler\n", dist->ops->name);*/ /* printf("pass %s sampler\n", dist_name(dist));*/ return true; } else { printf("fail %s sampler\n", dist->ops->name); printf("fail %s sampler\n", dist_name(dist)); return false; } } Loading Loading
src/core/or/circuitpadding.c +10 −6 Original line number Diff line number Diff line Loading @@ -545,7 +545,7 @@ circpad_distribution_sample(circpad_distribution_t dist) .a = dist.param1, .b = dist.param2, }; return uniform_sample(&my_uniform.base); return dist_sample(&my_uniform.base); } case CIRCPAD_DIST_LOGISTIC: { Loading @@ -555,7 +555,7 @@ circpad_distribution_sample(circpad_distribution_t dist) .mu = dist.param1, .sigma = dist.param2, }; return logistic_sample(&my_logistic.base); return dist_sample(&my_logistic.base); } case CIRCPAD_DIST_LOG_LOGISTIC: { Loading @@ -565,12 +565,16 @@ circpad_distribution_sample(circpad_distribution_t dist) .alpha = dist.param1, .beta = dist.param2, }; return log_logistic_sample(&my_log_logistic.base); return dist_sample(&my_log_logistic.base); } case CIRCPAD_DIST_GEOMETRIC: { /* param1 is 'p' (success probability) */ return geometric_sample(dist.param1); const struct geometric my_geometric = { .base = DIST_BASE(&geometric_ops), .p = dist.param1, }; return dist_sample(&my_geometric.base); } case CIRCPAD_DIST_WEIBULL: { Loading @@ -580,7 +584,7 @@ circpad_distribution_sample(circpad_distribution_t dist) .k = dist.param1, .lambda = dist.param2, }; return weibull_sample(&my_weibull.base); return dist_sample(&my_weibull.base); } case CIRCPAD_DIST_PARETO: { Loading @@ -591,7 +595,7 @@ circpad_distribution_sample(circpad_distribution_t dist) .sigma = dist.param1, .xi = dist.param2, }; return genpareto_sample(&my_genpareto.base); return dist_sample(&my_genpareto.base); } } Loading
src/lib/math/prob_distr.c +159 −70 Original line number Diff line number Diff line Loading @@ -1319,17 +1319,45 @@ sample_geometric(uint32_t s, double p0, double p) * (sample/cdf/sf/icdf/isf) as part of its dist_ops structure. */ /** Functions for uniform distribution */ const struct dist_ops uniform_ops = { .name = "uniform", .sample = uniform_sample, .cdf = uniform_cdf, .sf = uniform_sf, .icdf = uniform_icdf, .isf = uniform_isf, }; const char * dist_name(const struct dist *dist) { return dist->ops->name; } double dist_sample(const struct dist *dist) { return dist->ops->sample(dist); } double dist_cdf(const struct dist *dist, double x) { return dist->ops->cdf(dist, x); } double dist_sf(const struct dist *dist, double x) { return dist->ops->sf(dist, x); } double dist_icdf(const struct dist *dist, double p) { return dist->ops->icdf(dist, p); } double dist_isf(const struct dist *dist, double p) { return dist->ops->isf(dist, p); } /** Functions for uniform distribution */ static double uniform_sample(const struct dist *dist) { const struct uniform *U = const_container_of(dist, struct uniform, Loading @@ -1339,7 +1367,7 @@ uniform_sample(const struct dist *dist) return sample_uniform_interval(p0, U->a, U->b); } double static double uniform_cdf(const struct dist *dist, double x) { const struct uniform *U = const_container_of(dist, struct uniform, Loading @@ -1353,7 +1381,7 @@ uniform_cdf(const struct dist *dist, double x) return 1; } double static double uniform_sf(const struct dist *dist, double x) { const struct uniform *U = const_container_of(dist, struct uniform, Loading @@ -1367,7 +1395,7 @@ uniform_sf(const struct dist *dist, double x) return 1; } double static double uniform_icdf(const struct dist *dist, double p) { const struct uniform *U = const_container_of(dist, struct uniform, Loading @@ -1377,7 +1405,7 @@ uniform_icdf(const struct dist *dist, double p) return (p < 0.5 ? (U->a + w*p) : (U->b - w*(1 - p))); } double static double uniform_isf(const struct dist *dist, double p) { const struct uniform *U = const_container_of(dist, struct uniform, Loading @@ -1387,17 +1415,18 @@ uniform_isf(const struct dist *dist, double p) return (p < 0.5 ? (U->b - w*p) : (U->a + w*(1 - p))); } /** Functions for logistic distribution: */ const struct dist_ops logistic_ops = { .name = "logistic", .sample = logistic_sample, .cdf = logistic_cdf, .sf = logistic_sf, .icdf = logistic_icdf, .isf = logistic_isf, const struct dist_ops uniform_ops = { .name = "uniform", .sample = uniform_sample, .cdf = uniform_cdf, .sf = uniform_sf, .icdf = uniform_icdf, .isf = uniform_isf, }; double /** Functions for logistic distribution: */ static double logistic_sample(const struct dist *dist) { const struct logistic *L = const_container_of(dist, struct logistic, Loading @@ -1409,7 +1438,7 @@ logistic_sample(const struct dist *dist) return sample_logistic_locscale(s, t, p0, L->mu, L->sigma); } double static double logistic_cdf(const struct dist *dist, double x) { const struct logistic *L = const_container_of(dist, struct logistic, Loading @@ -1418,7 +1447,7 @@ logistic_cdf(const struct dist *dist, double x) return cdf_logistic(x, L->mu, L->sigma); } double static double logistic_sf(const struct dist *dist, double x) { const struct logistic *L = const_container_of(dist, struct logistic, Loading @@ -1427,7 +1456,7 @@ logistic_sf(const struct dist *dist, double x) return sf_logistic(x, L->mu, L->sigma); } double static double logistic_icdf(const struct dist *dist, double p) { const struct logistic *L = const_container_of(dist, struct logistic, Loading @@ -1436,7 +1465,7 @@ logistic_icdf(const struct dist *dist, double p) return icdf_logistic(p, L->mu, L->sigma); } double static double logistic_isf(const struct dist *dist, double p) { const struct logistic *L = const_container_of(dist, struct logistic, Loading @@ -1445,17 +1474,18 @@ logistic_isf(const struct dist *dist, double p) return isf_logistic(p, L->mu, L->sigma); } /** Functions for log-logistic distribution: */ const struct dist_ops log_logistic_ops = { .name = "log logistic", .sample = log_logistic_sample, .cdf = log_logistic_cdf, .sf = log_logistic_sf, .icdf = log_logistic_icdf, .isf = log_logistic_isf, const struct dist_ops logistic_ops = { .name = "logistic", .sample = logistic_sample, .cdf = logistic_cdf, .sf = logistic_sf, .icdf = logistic_icdf, .isf = logistic_isf, }; double /** Functions for log-logistic distribution: */ static double log_logistic_sample(const struct dist *dist) { const struct log_logistic *LL = const_container_of(dist, struct Loading @@ -1466,7 +1496,7 @@ log_logistic_sample(const struct dist *dist) return sample_log_logistic_scaleshape(s, p0, LL->alpha, LL->beta); } double static double log_logistic_cdf(const struct dist *dist, double x) { const struct log_logistic *LL = const_container_of(dist, Loading @@ -1475,7 +1505,7 @@ log_logistic_cdf(const struct dist *dist, double x) return cdf_log_logistic(x, LL->alpha, LL->beta); } double static double log_logistic_sf(const struct dist *dist, double x) { const struct log_logistic *LL = const_container_of(dist, Loading @@ -1484,7 +1514,7 @@ log_logistic_sf(const struct dist *dist, double x) return sf_log_logistic(x, LL->alpha, LL->beta); } double static double log_logistic_icdf(const struct dist *dist, double p) { const struct log_logistic *LL = const_container_of(dist, Loading @@ -1493,7 +1523,7 @@ log_logistic_icdf(const struct dist *dist, double p) return icdf_log_logistic(p, LL->alpha, LL->beta); } double static double log_logistic_isf(const struct dist *dist, double p) { const struct log_logistic *LL = const_container_of(dist, Loading @@ -1502,17 +1532,18 @@ log_logistic_isf(const struct dist *dist, double p) return isf_log_logistic(p, LL->alpha, LL->beta); } /** Functions for Weibull distribution */ const struct dist_ops weibull_ops = { .name = "Weibull", .sample = weibull_sample, .cdf = weibull_cdf, .sf = weibull_sf, .icdf = weibull_icdf, .isf = weibull_isf, const struct dist_ops log_logistic_ops = { .name = "log logistic", .sample = log_logistic_sample, .cdf = log_logistic_cdf, .sf = log_logistic_sf, .icdf = log_logistic_icdf, .isf = log_logistic_isf, }; double /** Functions for Weibull distribution */ static double weibull_sample(const struct dist *dist) { const struct weibull *W = const_container_of(dist, struct weibull, Loading @@ -1523,7 +1554,7 @@ weibull_sample(const struct dist *dist) return sample_weibull(s, p0, W->lambda, W->k); } double static double weibull_cdf(const struct dist *dist, double x) { const struct weibull *W = const_container_of(dist, struct weibull, Loading @@ -1532,7 +1563,7 @@ weibull_cdf(const struct dist *dist, double x) return cdf_weibull(x, W->lambda, W->k); } double static double weibull_sf(const struct dist *dist, double x) { const struct weibull *W = const_container_of(dist, struct weibull, Loading @@ -1541,7 +1572,7 @@ weibull_sf(const struct dist *dist, double x) return sf_weibull(x, W->lambda, W->k); } double static double weibull_icdf(const struct dist *dist, double p) { const struct weibull *W = const_container_of(dist, struct weibull, Loading @@ -1550,7 +1581,7 @@ weibull_icdf(const struct dist *dist, double p) return icdf_weibull(p, W->lambda, W->k); } double static double weibull_isf(const struct dist *dist, double p) { const struct weibull *W = const_container_of(dist, struct weibull, Loading @@ -1559,17 +1590,18 @@ weibull_isf(const struct dist *dist, double p) return isf_weibull(p, W->lambda, W->k); } /** Functions for generalized Pareto distributions */ const struct dist_ops genpareto_ops = { .name = "generalized Pareto", .sample = genpareto_sample, .cdf = genpareto_cdf, .sf = genpareto_sf, .icdf = genpareto_icdf, .isf = genpareto_isf, const struct dist_ops weibull_ops = { .name = "Weibull", .sample = weibull_sample, .cdf = weibull_cdf, .sf = weibull_sf, .icdf = weibull_icdf, .isf = weibull_isf, }; double /** Functions for generalized Pareto distributions */ static double genpareto_sample(const struct dist *dist) { const struct genpareto *GP = const_container_of(dist, struct genpareto, Loading @@ -1580,7 +1612,7 @@ genpareto_sample(const struct dist *dist) return sample_genpareto_locscale(s, p0, GP->mu, GP->sigma, GP->xi); } double static double genpareto_cdf(const struct dist *dist, double x) { const struct genpareto *GP = const_container_of(dist, struct genpareto, Loading @@ -1589,7 +1621,7 @@ genpareto_cdf(const struct dist *dist, double x) return cdf_genpareto(x, GP->mu, GP->sigma, GP->xi); } double static double genpareto_sf(const struct dist *dist, double x) { const struct genpareto *GP = const_container_of(dist, struct genpareto, Loading @@ -1598,7 +1630,7 @@ genpareto_sf(const struct dist *dist, double x) return sf_genpareto(x, GP->mu, GP->sigma, GP->xi); } double static double genpareto_icdf(const struct dist *dist, double p) { const struct genpareto *GP = const_container_of(dist, struct genpareto, Loading @@ -1607,7 +1639,7 @@ genpareto_icdf(const struct dist *dist, double p) return icdf_genpareto(p, GP->mu, GP->sigma, GP->xi); } double static double genpareto_isf(const struct dist *dist, double p) { const struct genpareto *GP = const_container_of(dist, struct genpareto, Loading @@ -1616,13 +1648,70 @@ genpareto_isf(const struct dist *dist, double p) return isf_genpareto(p, GP->mu, GP->sigma, GP->xi); } /* Deterministically sample from the geometric distribution with * per-trial success probability p. */ double geometric_sample(double p) const struct dist_ops genpareto_ops = { .name = "generalized Pareto", .sample = genpareto_sample, .cdf = genpareto_cdf, .sf = genpareto_sf, .icdf = genpareto_icdf, .isf = genpareto_isf, }; /** Functions for geometric distribution on number of trials before success */ static double geometric_sample(const struct dist *dist) { const struct geometric *G = const_container_of(dist, struct geometric, base); uint32_t s = crypto_rand_u32(); double p0 = random_uniform_01(); return sample_geometric(s, p0, p); return sample_geometric(s, p0, G->p); } static double geometric_cdf(const struct dist *dist, double x) { const struct geometric *G = const_container_of(dist, struct geometric, base); if (x < 1) return 0; /* 1 - (1 - p)^floor(x) = 1 - e^{floor(x) log(1 - p)} */ return -expm1(floor(x)*log1p(-G->p)); } static double geometric_sf(const struct dist *dist, double x) { const struct geometric *G = const_container_of(dist, struct geometric, base); if (x < 1) return 0; /* (1 - p)^floor(x) = e^{ceil(x) log(1 - p)} */ return exp(floor(x)*log1p(-G->p)); } static double geometric_icdf(const struct dist *dist, double p) { const struct geometric *G = const_container_of(dist, struct geometric, base); return log1p(-p)/log1p(-G->p); } static double geometric_isf(const struct dist *dist, double p) { const struct geometric *G = const_container_of(dist, struct geometric, base); return log(p)/log1p(-G->p); } const struct dist_ops geometric_ops = { .name = "geometric (1-based)", .sample = geometric_sample, .cdf = geometric_cdf, .sf = geometric_sf, .icdf = geometric_icdf, .isf = geometric_isf, };
src/lib/math/prob_distr.h +14 −32 Original line number Diff line number Diff line Loading @@ -21,6 +21,13 @@ struct dist { #define DIST_BASE(OPS) { .ops = (OPS) } const char *dist_name(const struct dist *); double dist_sample(const struct dist *); double dist_cdf(const struct dist *, double x); double dist_sf(const struct dist *, double x); double dist_icdf(const struct dist *, double p); double dist_isf(const struct dist *, double p); struct dist_ops { const char *name; double (*sample)(const struct dist *); Loading @@ -30,9 +37,14 @@ struct dist_ops { double (*isf)(const struct dist *, double p); }; /* Geometric distribution */ /* Geometric distribution on positive number of trials before first success */ double geometric_sample(double p); struct geometric { struct dist base; double p; /* success probability */ }; extern const struct dist_ops geometric_ops; /* Pareto distribution */ Loading @@ -43,12 +55,6 @@ struct genpareto { double xi; }; double genpareto_sample(const struct dist *dist); double genpareto_cdf(const struct dist *dist, double x); double genpareto_sf(const struct dist *dist, double x); double genpareto_icdf(const struct dist *dist, double p); double genpareto_isf(const struct dist *dist, double p); extern const struct dist_ops genpareto_ops; /* Weibull distribution */ Loading @@ -59,12 +65,6 @@ struct weibull { double k; }; double weibull_sample(const struct dist *dist); double weibull_cdf(const struct dist *dist, double x); double weibull_sf(const struct dist *dist, double x); double weibull_icdf(const struct dist *dist, double p); double weibull_isf(const struct dist *dist, double p); extern const struct dist_ops weibull_ops; /* Log-logistic distribution */ Loading @@ -75,12 +75,6 @@ struct log_logistic { double beta; }; double log_logistic_sample(const struct dist *dist); double log_logistic_cdf(const struct dist *dist, double x); double log_logistic_sf(const struct dist *dist, double x); double log_logistic_icdf(const struct dist *dist, double p); double log_logistic_isf(const struct dist *dist, double p); extern const struct dist_ops log_logistic_ops; /* Logistic distribution */ Loading @@ -91,12 +85,6 @@ struct logistic { double sigma; }; double logistic_sample(const struct dist *dist); double logistic_cdf(const struct dist *dist, double x); double logistic_sf(const struct dist *dist, double x); double logistic_icdf(const struct dist *dist, double p); double logistic_isf(const struct dist *dist, double p); extern const struct dist_ops logistic_ops; /* Uniform distribution */ Loading @@ -107,12 +95,6 @@ struct uniform { double b; }; double uniform_sample(const struct dist *dist); double uniform_cdf(const struct dist *dist, double x); double uniform_sf(const struct dist *dist, double x); double uniform_icdf(const struct dist *dist, double p); double uniform_isf(const struct dist *dist, double p); extern const struct dist_ops uniform_ops; /** Only by unittests */ Loading
src/test/test_prob_distr.c +13 −9 Original line number Diff line number Diff line Loading @@ -942,6 +942,10 @@ psi_test(const size_t C[PSI_DF], const double logP[PSI_DF], size_t N) static bool test_stochastic_geometric_impl(double p) { const struct geometric geometric = { .base = DIST_BASE(&geometric_ops), .p = p, }; double logP[PSI_DF] = {0}; unsigned ntry = NTRIALS, npass = 0; unsigned i; Loading @@ -958,7 +962,7 @@ test_stochastic_geometric_impl(double p) size_t C[PSI_DF] = {0}; for (j = 0; j < NSAMPLES; j++) { double n_tmp = geometric_sample(p); double n_tmp = dist_sample(&geometric.base); /* Must be an integer. (XXX -Wfloat-equal) */ tor_assert(ceil(n_tmp) <= n_tmp && ceil(n_tmp) >= n_tmp); Loading Loading @@ -1006,10 +1010,10 @@ test_stochastic_geometric_impl(double p) static void bin_cdfs(const struct dist *dist, double lo, double hi, double *logP, size_t n) { #define CDF(x) dist->ops->cdf(dist, x) #define SF(x) dist->ops->sf(dist, x) #define CDF(x) dist_cdf(dist, x) #define SF(x) dist_sf(dist, x) const double w = (hi - lo)/(n - 2); double halfway = dist->ops->icdf(dist, 0.5); double halfway = dist_icdf(dist, 0.5); double x_0, x_1; size_t i; size_t n2 = ceil_to_size_t((halfway - lo)/w); Loading Loading @@ -1057,7 +1061,7 @@ bin_samples(const struct dist *dist, double lo, double hi, size_t *C, size_t n) size_t i; for (i = 0; i < NSAMPLES; i++) { double x = dist->ops->sample(dist); double x = dist_sample(dist); size_t bin; if (x < lo) Loading @@ -1084,8 +1088,8 @@ test_psi_dist_sample(const struct dist *dist) { double logP[PSI_DF] = {0}; unsigned ntry = NTRIALS, npass = 0; double lo = dist->ops->icdf(dist, 1/(double)(PSI_DF + 2)); double hi = dist->ops->isf(dist, 1/(double)(PSI_DF + 2)); double lo = dist_icdf(dist, 1/(double)(PSI_DF + 2)); double hi = dist_isf(dist, 1/(double)(PSI_DF + 2)); /* Create the null hypothesis in logP */ bin_cdfs(dist, lo, hi, logP, PSI_DF); Loading @@ -1102,10 +1106,10 @@ test_psi_dist_sample(const struct dist *dist) /* Did we fail or succeed? */ if (npass >= NPASSES_MIN) { /* printf("pass %s sampler\n", dist->ops->name);*/ /* printf("pass %s sampler\n", dist_name(dist));*/ return true; } else { printf("fail %s sampler\n", dist->ops->name); printf("fail %s sampler\n", dist_name(dist)); return false; } } Loading