123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253 |
- /**
- * \file prob_distr.h
- *
- * \brief Header for prob_distr.c
- **/
- #ifndef TOR_PROB_DISTR_H
- #define TOR_PROB_DISTR_H
- #include "lib/cc/compat_compiler.h"
- #include "lib/cc/torint.h"
- #include "lib/testsupport/testsupport.h"
- /**
- * Container for distribution parameters for sampling, CDF, &c.
- */
- struct dist {
- const struct dist_ops *ops;
- };
- /**
- * Untyped initializer element for struct dist using the specified
- * struct dist_ops pointer. Don't actually use this directly -- use
- * the type-specific macro built out of DIST_BASE_TYPED below -- but if
- * you did use this directly, it would be something like:
- *
- * struct weibull mydist = {
- * DIST_BASE(&weibull_ops),
- * .lambda = ...,
- * .k = ...,
- * };
- *
- * Note there is NO COMPILER FEEDBACK if you accidentally do something
- * like
- *
- * struct geometric mydist = {
- * DIST_BASE(&weibull_ops),
- * ...
- * };
- */
- #define DIST_BASE(OPS) { .ops = (OPS) }
- /** A compile-time type-checking macro for use with DIST_BASE_TYPED.
- *
- * This macro works by checking that &OBJ is a pointer type that is the same
- * type (except for qualifiers) as (const TYPE *)&OBJ. It's a C constraint
- * violation (which requires a diagnostic) if two pointers are different types
- * and are subtracted. The sizeof() forces compile-time evaluation, and the
- * multiplication by zero is to discard the result of the sizeof() from the
- * expression.
- *
- * We define this conditionally to suppress false positives from
- * Coverity, which gets confused by the sizeof business.
- */
- #ifdef __COVERITY__
- #define TYPE_CHECK_OBJ(OPS, OBJ, TYPE) 0
- #else
- #define TYPE_CHECK_OBJ(OPS, OBJ, TYPE) \
- (0*sizeof(&(OBJ) - (const TYPE *)&(OBJ)))
- #endif /* defined(__COVERITY__) */
- /**
- * Typed initializer element for struct dist using the specified struct
- * dist_ops pointer. Don't actually use this directly -- use a
- * type-specific macro built out of it -- but if you did use this
- * directly, it would be something like:
- *
- * struct weibull mydist = {
- * DIST_BASE_TYPED(&weibull_ops, mydist, struct weibull),
- * .lambda = ...,
- * .k = ...,
- * };
- *
- * If you want to define a distribution type, define a canonical set of
- * operations and define a type-specific initializer element like so:
- *
- * struct foo {
- * struct dist base;
- * int omega;
- * double tau;
- * double phi;
- * };
- *
- * struct dist_ops foo_ops = ...;
- *
- * #define FOO(OBJ) DIST_BASE_TYPED(&foo_ops, OBJ, struct foo)
- *
- * Then users can do:
- *
- * struct foo mydist = {
- * FOO(mydist),
- * .omega = ...,
- * .tau = ...,
- * .phi = ...,
- * };
- *
- * If you accidentally write
- *
- * struct bar mydist = {
- * FOO(mydist),
- * ...
- * };
- *
- * then the compiler will report a type mismatch in the sizeof
- * expression, which otherwise evaporates at runtime.
- */
- #define DIST_BASE_TYPED(OPS, OBJ, TYPE) \
- DIST_BASE((OPS) + TYPE_CHECK_OBJ(OPS,OBJ,TYPE))
- /**
- * Generic operations on distributions. These simply defer to the
- * corresponding dist_ops function. In the parlance of C++, these call
- * virtual member functions.
- */
- 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);
- /**
- * Set of operations on a potentially parametric family of
- * distributions. In the parlance of C++, this would be called a
- * `vtable' and the members are virtual member functions.
- */
- struct dist_ops {
- const char *name;
- double (*sample)(const struct dist *);
- double (*cdf)(const struct dist *, double x);
- double (*sf)(const struct dist *, double x);
- double (*icdf)(const struct dist *, double p);
- double (*isf)(const struct dist *, double p);
- };
- /* Geometric distribution on positive number of trials before first success */
- struct geometric {
- struct dist base;
- double p; /* success probability */
- };
- extern const struct dist_ops geometric_ops;
- #define GEOMETRIC(OBJ) \
- DIST_BASE_TYPED(&geometric_ops, OBJ, struct geometric)
- /* Pareto distribution */
- struct genpareto {
- struct dist base;
- double mu;
- double sigma;
- double xi;
- };
- extern const struct dist_ops genpareto_ops;
- #define GENPARETO(OBJ) \
- DIST_BASE_TYPED(&genpareto_ops, OBJ, struct genpareto)
- /* Weibull distribution */
- struct weibull {
- struct dist base;
- double lambda;
- double k;
- };
- extern const struct dist_ops weibull_ops;
- #define WEIBULL(OBJ) \
- DIST_BASE_TYPED(&weibull_ops, OBJ, struct weibull)
- /* Log-logistic distribution */
- struct log_logistic {
- struct dist base;
- double alpha;
- double beta;
- };
- extern const struct dist_ops log_logistic_ops;
- #define LOG_LOGISTIC(OBJ) \
- DIST_BASE_TYPED(&log_logistic_ops, OBJ, struct log_logistic)
- /* Logistic distribution */
- struct logistic {
- struct dist base;
- double mu;
- double sigma;
- };
- extern const struct dist_ops logistic_ops;
- #define LOGISTIC(OBJ) \
- DIST_BASE_TYPED(&logistic_ops, OBJ, struct logistic)
- /* Uniform distribution */
- struct uniform {
- struct dist base;
- double a;
- double b;
- };
- extern const struct dist_ops uniform_ops;
- #define UNIFORM(OBJ) \
- DIST_BASE_TYPED(&uniform_ops, OBJ, struct uniform)
- /** Only by unittests */
- #ifdef PROB_DISTR_PRIVATE
- STATIC double logithalf(double p0);
- STATIC double logit(double p);
- STATIC double random_uniform_01(void);
- STATIC double logistic(double x);
- STATIC double cdf_logistic(double x, double mu, double sigma);
- STATIC double sf_logistic(double x, double mu, double sigma);
- STATIC double icdf_logistic(double p, double mu, double sigma);
- STATIC double isf_logistic(double p, double mu, double sigma);
- STATIC double sample_logistic(uint32_t s, double t, double p0);
- STATIC double cdf_log_logistic(double x, double alpha, double beta);
- STATIC double sf_log_logistic(double x, double alpha, double beta);
- STATIC double icdf_log_logistic(double p, double alpha, double beta);
- STATIC double isf_log_logistic(double p, double alpha, double beta);
- STATIC double sample_log_logistic(uint32_t s, double p0);
- STATIC double cdf_weibull(double x, double lambda, double k);
- STATIC double sf_weibull(double x, double lambda, double k);
- STATIC double icdf_weibull(double p, double lambda, double k);
- STATIC double isf_weibull(double p, double lambda, double k);
- STATIC double sample_weibull(uint32_t s, double p0, double lambda, double k);
- STATIC double sample_uniform_interval(double p0, double a, double b);
- STATIC double cdf_genpareto(double x, double mu, double sigma, double xi);
- STATIC double sf_genpareto(double x, double mu, double sigma, double xi);
- STATIC double icdf_genpareto(double p, double mu, double sigma, double xi);
- STATIC double isf_genpareto(double p, double mu, double sigma, double xi);
- STATIC double sample_genpareto(uint32_t s, double p0, double xi);
- #endif /* defined(PROB_DISTR_PRIVATE) */
- #endif /* !defined(TOR_PROB_DISTR_H) */
|