prob_distr.h 7.0 KB

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