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) */