tor

The Tor anonymity network
git clone https://git.dasho.dev/tor.git
Log | Files | Refs | README | LICENSE

prob_distr.h (7341B)


      1 /**
      2 * \file prob_distr.h
      3 *
      4 * \brief Header for prob_distr.c
      5 **/
      6 
      7 #ifndef TOR_PROB_DISTR_H
      8 #define TOR_PROB_DISTR_H
      9 
     10 #include "lib/cc/compat_compiler.h"
     11 #include "lib/cc/torint.h"
     12 #include "lib/testsupport/testsupport.h"
     13 
     14 /**
     15 * Container for distribution parameters for sampling, CDF, &c.
     16 */
     17 struct dist_t {
     18  const struct dist_ops_t *ops;
     19 };
     20 
     21 /**
     22 * Untyped initializer element for struct dist_t using the specified
     23 * struct dist_ops_t pointer.  Don't actually use this directly -- use
     24 * the type-specific macro built out of DIST_BASE_TYPED below -- but if
     25 * you did use this directly, it would be something like:
     26 *
     27 *   struct weibull mydist = {
     28 *     DIST_BASE(&weibull_ops),
     29 *     .lambda = ...,
     30 *     .k = ...,
     31 *   };
     32 *
     33 * Note there is NO COMPILER FEEDBACK if you accidentally do something
     34 * like
     35 *
     36 *   struct geometric mydist = {
     37 *     DIST_BASE(&weibull_ops),
     38 *     ...
     39 *   };
     40 */
     41 #define DIST_BASE(OPS)  { .ops = (OPS) }
     42 
     43 /** A compile-time type-checking macro for use with DIST_BASE_TYPED.
     44 *
     45 *  This macro works by checking that &OBJ is a pointer type that is the same
     46 *  type (except for qualifiers) as (const TYPE *)&OBJ. It's a C constraint
     47 *  violation (which requires a diagnostic) if two pointers are different types
     48 *  and are subtracted. The sizeof() forces compile-time evaluation, and the
     49 *  multiplication by zero is to discard the result of the sizeof() from the
     50 *  expression.
     51 *
     52 *  We define this conditionally to suppress false positives from
     53 *  Coverity, which gets confused by the sizeof business.
     54 */
     55 #ifdef __COVERITY__
     56 #define TYPE_CHECK_OBJ(OPS, OBJ, TYPE) 0
     57 #else
     58 #define TYPE_CHECK_OBJ(OPS, OBJ, TYPE) \
     59  (0*sizeof(&(OBJ) - (const TYPE *)&(OBJ)))
     60 #endif /* defined(__COVERITY__) */
     61 
     62 /**
     63 * Typed initializer element for struct dist_t using the specified struct
     64 * dist_ops_t pointer.  Don't actually use this directly -- use a
     65 * type-specific macro built out of it -- but if you did use this
     66 * directly, it would be something like:
     67 *
     68 *     struct weibull mydist = {
     69 *       DIST_BASE_TYPED(&weibull_ops, mydist, struct weibull_t),
     70 *       .lambda = ...,
     71 *       .k = ...,
     72 *     };
     73 *
     74 * If you want to define a distribution type, define a canonical set of
     75 * operations and define a type-specific initializer element like so:
     76 *
     77 *     struct foo_t {
     78 *       struct dist_t base;
     79 *       int omega;
     80 *       double tau;
     81 *       double phi;
     82 *     };
     83 *
     84 *     struct dist_ops_t foo_ops = ...;
     85 *
     86 *     #define FOO(OBJ) DIST_BASE_TYPED(&foo_ops, OBJ, struct foo_t)
     87 *
     88 * Then users can do:
     89 *
     90 *     struct foo_t mydist = {
     91 *       FOO(mydist),
     92 *       .omega = ...,
     93 *       .tau = ...,
     94 *       .phi = ...,
     95 *     };
     96 *
     97 * If you accidentally write
     98 *
     99 *     struct bar_t mydist = {
    100 *       FOO(mydist),
    101 *       ...
    102 *     };
    103 *
    104 * then the compiler will report a type mismatch in the sizeof
    105 * expression, which otherwise evaporates at runtime.
    106 */
    107 #define DIST_BASE_TYPED(OPS, OBJ, TYPE)                         \
    108  DIST_BASE((OPS) + TYPE_CHECK_OBJ(OPS,OBJ,TYPE))
    109 
    110 /**
    111 * Generic operations on distributions.  These simply defer to the
    112 * corresponding dist_ops_t function.  In the parlance of C++, these call
    113 * virtual member functions.
    114 */
    115 const char *dist_name(const struct dist_t *);
    116 double dist_sample(const struct dist_t *);
    117 double dist_cdf(const struct dist_t *, double x);
    118 double dist_sf(const struct dist_t *, double x);
    119 double dist_icdf(const struct dist_t *, double p);
    120 double dist_isf(const struct dist_t *, double p);
    121 
    122 /**
    123 * Set of operations on a potentially parametric family of
    124 * distributions.  In the parlance of C++, this would be called a
    125 * `vtable' and the members are virtual member functions.
    126 */
    127 struct dist_ops_t {
    128  const char *name;
    129  double (*sample)(const struct dist_t *);
    130  double (*cdf)(const struct dist_t *, double x);
    131  double (*sf)(const struct dist_t *, double x);
    132  double (*icdf)(const struct dist_t *, double p);
    133  double (*isf)(const struct dist_t *, double p);
    134 };
    135 
    136 /* Geometric distribution on positive number of trials before first success */
    137 
    138 struct geometric_t {
    139  struct dist_t base;
    140  double p; /* success probability */
    141 };
    142 
    143 extern const struct dist_ops_t geometric_ops;
    144 
    145 #define GEOMETRIC(OBJ)                                      \
    146  DIST_BASE_TYPED(&geometric_ops, OBJ, struct geometric_t)
    147 
    148 /* Pareto distribution */
    149 
    150 struct genpareto_t {
    151  struct dist_t base;
    152  double mu;
    153  double sigma;
    154  double xi;
    155 };
    156 
    157 extern const struct dist_ops_t genpareto_ops;
    158 
    159 #define GENPARETO(OBJ)                                      \
    160  DIST_BASE_TYPED(&genpareto_ops, OBJ, struct genpareto_t)
    161 
    162 /* Weibull distribution */
    163 
    164 struct weibull_t {
    165  struct dist_t base;
    166  double lambda;
    167  double k;
    168 };
    169 
    170 extern const struct dist_ops_t weibull_ops;
    171 
    172 #define WEIBULL(OBJ)                                    \
    173  DIST_BASE_TYPED(&weibull_ops, OBJ, struct weibull_t)
    174 
    175 /* Log-logistic distribution */
    176 
    177 struct log_logistic_t {
    178  struct dist_t base;
    179  double alpha;
    180  double beta;
    181 };
    182 
    183 extern const struct dist_ops_t log_logistic_ops;
    184 
    185 #define LOG_LOGISTIC(OBJ)                                       \
    186  DIST_BASE_TYPED(&log_logistic_ops, OBJ, struct log_logistic_t)
    187 
    188 /* Logistic distribution */
    189 
    190 struct logistic_t {
    191  struct dist_t base;
    192  double mu;
    193  double sigma;
    194 };
    195 
    196 extern const struct dist_ops_t logistic_ops;
    197 
    198 #define LOGISTIC(OBJ)                                   \
    199  DIST_BASE_TYPED(&logistic_ops, OBJ, struct logistic_t)
    200 
    201 /* Uniform distribution */
    202 
    203 struct uniform_t {
    204  struct dist_t base;
    205  double a;
    206  double b;
    207 };
    208 
    209 extern const struct dist_ops_t uniform_ops;
    210 
    211 #define UNIFORM(OBJ)                                    \
    212  DIST_BASE_TYPED(&uniform_ops, OBJ, struct uniform_t)
    213 
    214 /** Only by unittests */
    215 
    216 #ifdef PROB_DISTR_PRIVATE
    217 
    218 STATIC double logithalf(double p0);
    219 STATIC double logit(double p);
    220 
    221 STATIC double random_uniform_01(void);
    222 
    223 STATIC double logistic(double x);
    224 STATIC double cdf_logistic(double x, double mu, double sigma);
    225 STATIC double sf_logistic(double x, double mu, double sigma);
    226 STATIC double icdf_logistic(double p, double mu, double sigma);
    227 STATIC double isf_logistic(double p, double mu, double sigma);
    228 STATIC double sample_logistic(uint32_t s, double t, double p0);
    229 
    230 STATIC double cdf_log_logistic(double x, double alpha, double beta);
    231 STATIC double sf_log_logistic(double x, double alpha, double beta);
    232 STATIC double icdf_log_logistic(double p, double alpha, double beta);
    233 STATIC double isf_log_logistic(double p, double alpha, double beta);
    234 STATIC double sample_log_logistic(uint32_t s, double p0);
    235 
    236 STATIC double cdf_weibull(double x, double lambda, double k);
    237 STATIC double sf_weibull(double x, double lambda, double k);
    238 STATIC double icdf_weibull(double p, double lambda, double k);
    239 STATIC double isf_weibull(double p, double lambda, double k);
    240 STATIC double sample_weibull(uint32_t s, double p0, double lambda, double k);
    241 
    242 STATIC double sample_uniform_interval(double p0, double a, double b);
    243 
    244 STATIC double cdf_genpareto(double x, double mu, double sigma, double xi);
    245 STATIC double sf_genpareto(double x, double mu, double sigma, double xi);
    246 STATIC double icdf_genpareto(double p, double mu, double sigma, double xi);
    247 STATIC double isf_genpareto(double p, double mu, double sigma, double xi);
    248 STATIC double sample_genpareto(uint32_t s, double p0, double xi);
    249 
    250 #endif /* defined(PROB_DISTR_PRIVATE) */
    251 
    252 #endif /* !defined(TOR_PROB_DISTR_H) */