mirror of
https://gitlab.torproject.org/tpo/core/tor.git
synced 2024-11-10 21:23:58 +01:00
prob_distr: Implement type-safe downcasting functions.
This commit is contained in:
parent
58fd864a85
commit
8d9f81bc9c
@ -46,26 +46,27 @@
|
||||
|
||||
#include "lib/crypt_ops/crypto_rand.h"
|
||||
#include "lib/cc/ctassert.h"
|
||||
#include "lib/log/util_bug.h"
|
||||
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
#include <stddef.h>
|
||||
|
||||
/** Validators for downcasting macros below */
|
||||
#define validate_container_of(PTR, TYPE, FIELD) \
|
||||
(0 * sizeof((PTR) - &((TYPE *)(((char *)(PTR)) - \
|
||||
offsetof(TYPE, FIELD)))->FIELD))
|
||||
#define validate_const_container_of(PTR, TYPE, FIELD) \
|
||||
(0 * sizeof((PTR) - &((const TYPE *)(((const char *)(PTR)) - \
|
||||
offsetof(TYPE, FIELD)))->FIELD))
|
||||
/** Downcasting macro */
|
||||
#define container_of(PTR, TYPE, FIELD) \
|
||||
((TYPE *)(((char *)(PTR)) - offsetof(TYPE, FIELD)) \
|
||||
+ validate_container_of(PTR, TYPE, FIELD))
|
||||
/** Constified downcasting macro */
|
||||
#define const_container_of(PTR, TYPE, FIELD) \
|
||||
((const TYPE *)(((const char *)(PTR)) - offsetof(TYPE, FIELD)) \
|
||||
+ validate_const_container_of(PTR, TYPE, FIELD))
|
||||
/** Declare a function that downcasts from a generic dist struct to the actual
|
||||
* subtype probablity distribution it represents. */
|
||||
#define DECLARE_PROB_DISTR_DOWNCAST_FN(name) \
|
||||
static inline \
|
||||
const struct name * \
|
||||
dist_to_const_##name(const struct dist *obj) { \
|
||||
tor_assert(obj->ops == &name##_ops); \
|
||||
return SUBTYPE_P(obj, struct name, base); \
|
||||
}
|
||||
DECLARE_PROB_DISTR_DOWNCAST_FN(uniform)
|
||||
DECLARE_PROB_DISTR_DOWNCAST_FN(geometric)
|
||||
DECLARE_PROB_DISTR_DOWNCAST_FN(logistic)
|
||||
DECLARE_PROB_DISTR_DOWNCAST_FN(log_logistic)
|
||||
DECLARE_PROB_DISTR_DOWNCAST_FN(genpareto)
|
||||
DECLARE_PROB_DISTR_DOWNCAST_FN(weibull)
|
||||
|
||||
/**
|
||||
* Count number of one bits in 32-bit word.
|
||||
@ -1360,8 +1361,7 @@ dist_isf(const struct dist *dist, double p)
|
||||
static double
|
||||
uniform_sample(const struct dist *dist)
|
||||
{
|
||||
const struct uniform *U = const_container_of(dist, struct uniform,
|
||||
base);
|
||||
const struct uniform *U = dist_to_const_uniform(dist);
|
||||
double p0 = random_uniform_01();
|
||||
|
||||
return sample_uniform_interval(p0, U->a, U->b);
|
||||
@ -1370,9 +1370,7 @@ uniform_sample(const struct dist *dist)
|
||||
static double
|
||||
uniform_cdf(const struct dist *dist, double x)
|
||||
{
|
||||
const struct uniform *U = const_container_of(dist, struct uniform,
|
||||
base);
|
||||
|
||||
const struct uniform *U = dist_to_const_uniform(dist);
|
||||
if (x < U->a)
|
||||
return 0;
|
||||
else if (x < U->b)
|
||||
@ -1384,8 +1382,7 @@ uniform_cdf(const struct dist *dist, double x)
|
||||
static double
|
||||
uniform_sf(const struct dist *dist, double x)
|
||||
{
|
||||
const struct uniform *U = const_container_of(dist, struct uniform,
|
||||
base);
|
||||
const struct uniform *U = dist_to_const_uniform(dist);
|
||||
|
||||
if (x > U->b)
|
||||
return 0;
|
||||
@ -1398,8 +1395,7 @@ uniform_sf(const struct dist *dist, double x)
|
||||
static double
|
||||
uniform_icdf(const struct dist *dist, double p)
|
||||
{
|
||||
const struct uniform *U = const_container_of(dist, struct uniform,
|
||||
base);
|
||||
const struct uniform *U = dist_to_const_uniform(dist);
|
||||
double w = U->b - U->a;
|
||||
|
||||
return (p < 0.5 ? (U->a + w*p) : (U->b - w*(1 - p)));
|
||||
@ -1408,8 +1404,7 @@ uniform_icdf(const struct dist *dist, double p)
|
||||
static double
|
||||
uniform_isf(const struct dist *dist, double p)
|
||||
{
|
||||
const struct uniform *U = const_container_of(dist, struct uniform,
|
||||
base);
|
||||
const struct uniform *U = dist_to_const_uniform(dist);
|
||||
double w = U->b - U->a;
|
||||
|
||||
return (p < 0.5 ? (U->b - w*p) : (U->a + w*(1 - p)));
|
||||
@ -1429,8 +1424,7 @@ const struct dist_ops uniform_ops = {
|
||||
static double
|
||||
logistic_sample(const struct dist *dist)
|
||||
{
|
||||
const struct logistic *L = const_container_of(dist, struct logistic,
|
||||
base);
|
||||
const struct logistic *L = dist_to_const_logistic(dist);
|
||||
uint32_t s = crypto_rand_u32();
|
||||
double t = random_uniform_01();
|
||||
double p0 = random_uniform_01();
|
||||
@ -1441,36 +1435,28 @@ logistic_sample(const struct dist *dist)
|
||||
static double
|
||||
logistic_cdf(const struct dist *dist, double x)
|
||||
{
|
||||
const struct logistic *L = const_container_of(dist, struct logistic,
|
||||
base);
|
||||
|
||||
const struct logistic *L = dist_to_const_logistic(dist);
|
||||
return cdf_logistic(x, L->mu, L->sigma);
|
||||
}
|
||||
|
||||
static double
|
||||
logistic_sf(const struct dist *dist, double x)
|
||||
{
|
||||
const struct logistic *L = const_container_of(dist, struct logistic,
|
||||
base);
|
||||
|
||||
const struct logistic *L = dist_to_const_logistic(dist);
|
||||
return sf_logistic(x, L->mu, L->sigma);
|
||||
}
|
||||
|
||||
static double
|
||||
logistic_icdf(const struct dist *dist, double p)
|
||||
{
|
||||
const struct logistic *L = const_container_of(dist, struct logistic,
|
||||
base);
|
||||
|
||||
const struct logistic *L = dist_to_const_logistic(dist);
|
||||
return icdf_logistic(p, L->mu, L->sigma);
|
||||
}
|
||||
|
||||
static double
|
||||
logistic_isf(const struct dist *dist, double p)
|
||||
{
|
||||
const struct logistic *L = const_container_of(dist, struct logistic,
|
||||
base);
|
||||
|
||||
const struct logistic *L = dist_to_const_logistic(dist);
|
||||
return isf_logistic(p, L->mu, L->sigma);
|
||||
}
|
||||
|
||||
@ -1488,8 +1474,7 @@ const struct dist_ops logistic_ops = {
|
||||
static double
|
||||
log_logistic_sample(const struct dist *dist)
|
||||
{
|
||||
const struct log_logistic *LL = const_container_of(dist, struct
|
||||
log_logistic, base);
|
||||
const struct log_logistic *LL = dist_to_const_log_logistic(dist);
|
||||
uint32_t s = crypto_rand_u32();
|
||||
double p0 = random_uniform_01();
|
||||
|
||||
@ -1499,36 +1484,28 @@ log_logistic_sample(const struct dist *dist)
|
||||
static double
|
||||
log_logistic_cdf(const struct dist *dist, double x)
|
||||
{
|
||||
const struct log_logistic *LL = const_container_of(dist,
|
||||
struct log_logistic, base);
|
||||
|
||||
const struct log_logistic *LL = dist_to_const_log_logistic(dist);
|
||||
return cdf_log_logistic(x, LL->alpha, LL->beta);
|
||||
}
|
||||
|
||||
static double
|
||||
log_logistic_sf(const struct dist *dist, double x)
|
||||
{
|
||||
const struct log_logistic *LL = const_container_of(dist,
|
||||
struct log_logistic, base);
|
||||
|
||||
const struct log_logistic *LL = dist_to_const_log_logistic(dist);
|
||||
return sf_log_logistic(x, LL->alpha, LL->beta);
|
||||
}
|
||||
|
||||
static double
|
||||
log_logistic_icdf(const struct dist *dist, double p)
|
||||
{
|
||||
const struct log_logistic *LL = const_container_of(dist,
|
||||
struct log_logistic, base);
|
||||
|
||||
const struct log_logistic *LL = dist_to_const_log_logistic(dist);
|
||||
return icdf_log_logistic(p, LL->alpha, LL->beta);
|
||||
}
|
||||
|
||||
static double
|
||||
log_logistic_isf(const struct dist *dist, double p)
|
||||
{
|
||||
const struct log_logistic *LL = const_container_of(dist,
|
||||
struct log_logistic, base);
|
||||
|
||||
const struct log_logistic *LL = dist_to_const_log_logistic(dist);
|
||||
return isf_log_logistic(p, LL->alpha, LL->beta);
|
||||
}
|
||||
|
||||
@ -1546,8 +1523,7 @@ const struct dist_ops log_logistic_ops = {
|
||||
static double
|
||||
weibull_sample(const struct dist *dist)
|
||||
{
|
||||
const struct weibull *W = const_container_of(dist, struct weibull,
|
||||
base);
|
||||
const struct weibull *W = dist_to_const_weibull(dist);
|
||||
uint32_t s = crypto_rand_u32();
|
||||
double p0 = random_uniform_01();
|
||||
|
||||
@ -1557,36 +1533,28 @@ weibull_sample(const struct dist *dist)
|
||||
static double
|
||||
weibull_cdf(const struct dist *dist, double x)
|
||||
{
|
||||
const struct weibull *W = const_container_of(dist, struct weibull,
|
||||
base);
|
||||
|
||||
const struct weibull *W = dist_to_const_weibull(dist);
|
||||
return cdf_weibull(x, W->lambda, W->k);
|
||||
}
|
||||
|
||||
static double
|
||||
weibull_sf(const struct dist *dist, double x)
|
||||
{
|
||||
const struct weibull *W = const_container_of(dist, struct weibull,
|
||||
base);
|
||||
|
||||
const struct weibull *W = dist_to_const_weibull(dist);
|
||||
return sf_weibull(x, W->lambda, W->k);
|
||||
}
|
||||
|
||||
static double
|
||||
weibull_icdf(const struct dist *dist, double p)
|
||||
{
|
||||
const struct weibull *W = const_container_of(dist, struct weibull,
|
||||
base);
|
||||
|
||||
const struct weibull *W = dist_to_const_weibull(dist);
|
||||
return icdf_weibull(p, W->lambda, W->k);
|
||||
}
|
||||
|
||||
static double
|
||||
weibull_isf(const struct dist *dist, double p)
|
||||
{
|
||||
const struct weibull *W = const_container_of(dist, struct weibull,
|
||||
base);
|
||||
|
||||
const struct weibull *W = dist_to_const_weibull(dist);
|
||||
return isf_weibull(p, W->lambda, W->k);
|
||||
}
|
||||
|
||||
@ -1604,8 +1572,7 @@ const struct dist_ops weibull_ops = {
|
||||
static double
|
||||
genpareto_sample(const struct dist *dist)
|
||||
{
|
||||
const struct genpareto *GP = const_container_of(dist, struct genpareto,
|
||||
base);
|
||||
const struct genpareto *GP = dist_to_const_genpareto(dist);
|
||||
uint32_t s = crypto_rand_u32();
|
||||
double p0 = random_uniform_01();
|
||||
|
||||
@ -1615,36 +1582,28 @@ genpareto_sample(const struct dist *dist)
|
||||
static double
|
||||
genpareto_cdf(const struct dist *dist, double x)
|
||||
{
|
||||
const struct genpareto *GP = const_container_of(dist, struct genpareto,
|
||||
base);
|
||||
|
||||
const struct genpareto *GP = dist_to_const_genpareto(dist);
|
||||
return cdf_genpareto(x, GP->mu, GP->sigma, GP->xi);
|
||||
}
|
||||
|
||||
static double
|
||||
genpareto_sf(const struct dist *dist, double x)
|
||||
{
|
||||
const struct genpareto *GP = const_container_of(dist, struct genpareto,
|
||||
base);
|
||||
|
||||
const struct genpareto *GP = dist_to_const_genpareto(dist);
|
||||
return sf_genpareto(x, GP->mu, GP->sigma, GP->xi);
|
||||
}
|
||||
|
||||
static double
|
||||
genpareto_icdf(const struct dist *dist, double p)
|
||||
{
|
||||
const struct genpareto *GP = const_container_of(dist, struct genpareto,
|
||||
base);
|
||||
|
||||
const struct genpareto *GP = dist_to_const_genpareto(dist);
|
||||
return icdf_genpareto(p, GP->mu, GP->sigma, GP->xi);
|
||||
}
|
||||
|
||||
static double
|
||||
genpareto_isf(const struct dist *dist, double p)
|
||||
{
|
||||
const struct genpareto *GP = const_container_of(dist, struct genpareto,
|
||||
base);
|
||||
|
||||
const struct genpareto *GP = dist_to_const_genpareto(dist);
|
||||
return isf_genpareto(p, GP->mu, GP->sigma, GP->xi);
|
||||
}
|
||||
|
||||
@ -1662,7 +1621,7 @@ const struct dist_ops genpareto_ops = {
|
||||
static double
|
||||
geometric_sample(const struct dist *dist)
|
||||
{
|
||||
const struct geometric *G = const_container_of(dist, struct geometric, base);
|
||||
const struct geometric *G = dist_to_const_geometric(dist);
|
||||
uint32_t s = crypto_rand_u32();
|
||||
double p0 = random_uniform_01();
|
||||
|
||||
@ -1672,7 +1631,7 @@ geometric_sample(const struct dist *dist)
|
||||
static double
|
||||
geometric_cdf(const struct dist *dist, double x)
|
||||
{
|
||||
const struct geometric *G = const_container_of(dist, struct geometric, base);
|
||||
const struct geometric *G = dist_to_const_geometric(dist);
|
||||
|
||||
if (x < 1)
|
||||
return 0;
|
||||
@ -1683,7 +1642,7 @@ geometric_cdf(const struct dist *dist, double x)
|
||||
static double
|
||||
geometric_sf(const struct dist *dist, double x)
|
||||
{
|
||||
const struct geometric *G = const_container_of(dist, struct geometric, base);
|
||||
const struct geometric *G = dist_to_const_geometric(dist);
|
||||
|
||||
if (x < 1)
|
||||
return 0;
|
||||
@ -1694,7 +1653,7 @@ geometric_sf(const struct dist *dist, double x)
|
||||
static double
|
||||
geometric_icdf(const struct dist *dist, double p)
|
||||
{
|
||||
const struct geometric *G = const_container_of(dist, struct geometric, base);
|
||||
const struct geometric *G = dist_to_const_geometric(dist);
|
||||
|
||||
return log1p(-p)/log1p(-G->p);
|
||||
}
|
||||
@ -1702,7 +1661,7 @@ geometric_icdf(const struct dist *dist, double p)
|
||||
static double
|
||||
geometric_isf(const struct dist *dist, double p)
|
||||
{
|
||||
const struct geometric *G = const_container_of(dist, struct geometric, base);
|
||||
const struct geometric *G = dist_to_const_geometric(dist);
|
||||
|
||||
return log(p)/log1p(-G->p);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user