LCOV - code coverage report
Current view: top level - core/src/lib/random - random.c Hit Total Coverage
Test: ROOT-Sim master Documentation Coverage Lines: 6 11 54.5 %
Date: 2021-03-25 15:11:55

          Line data    Source code
       1           1 : /**
       2             :  * @file lib/random/random.c
       3             :  *
       4             :  * @brief Random Number Generators
       5             :  *
       6             :  * Piece-Wise Deterministic Random Number Generators.
       7             :  *
       8             :  * SPDX-FileCopyrightText: 2008-2021 HPDCS Group <rootsim@googlegroups.com>
       9             :  * SPDX-License-Identifier: GPL-3.0-only
      10             :  */
      11             : #include <lib/random/random.h>
      12             : 
      13             : #include <core/intrinsics.h>
      14             : #include <lib/lib_internal.h>
      15             : #include <lib/random/xoroshiro.h>
      16             : 
      17             : #include <math.h>
      18             : #include <memory.h>
      19             : 
      20           0 : void random_lib_lp_init(void)
      21             : {
      22             :         uint64_t seed = global_config.prng_seed;
      23             :         lp_id_t lid = lp_id_get();
      24             :         struct lib_ctx *ctx = lib_ctx_get();
      25             :         random_init(ctx->rng_s, lid, seed);
      26             :         ctx->unif = NAN;
      27             : }
      28             : 
      29           0 : double Random(void)
      30             : {
      31             :         struct lib_ctx *ctx = lib_ctx_get();
      32             :         uint64_t u_val = random_u64(ctx->rng_s);
      33             :         if (unlikely(!u_val))
      34             :                 return 0.0;
      35             : 
      36             :         double ret = 0.0;
      37             :         unsigned lzs = intrinsics_clz(u_val) + 1;
      38             :         u_val <<= lzs;
      39             :         u_val >>= 12;
      40             : 
      41             :         uint64_t exp = 1023 - lzs;
      42             :         u_val |= exp << 52;
      43             : 
      44             :         memcpy(&ret, &u_val, sizeof(double));
      45             :         return ret;
      46             : }
      47             : 
      48           0 : uint64_t RandomU64(void)
      49             : {
      50             :         struct lib_ctx *ctx = lib_ctx_get();
      51             :         return random_u64(ctx->rng_s);
      52             : }
      53             : 
      54             : /**
      55             :  * Return a random number according to an Exponential distribution.
      56             :  * The mean value of the distribution must be passed as the mean value.
      57             :  *
      58             :  * @param mean Mean value of the distribution
      59             :  * @return A random number
      60             :  */
      61           1 : double Expent(double mean)
      62             : {
      63             :         if (unlikely(mean < 0)) {
      64             :                 log_log(LOG_WARN, "Passed a negative mean into Expent()");
      65             :         }
      66             :         return -mean * log(1 - Random());
      67             : }
      68             : 
      69             : /**
      70             :  * Return a random number according to a Standard Normal Distribution
      71             :  *
      72             :  * @return A random number
      73             :  */
      74           1 : double Normal(void)
      75             : {
      76             :         struct lib_ctx *ctx = lib_ctx_get();
      77             :         if (isnan(ctx->unif)) {
      78             :                 double v1, v2, rsq;
      79             :                 do {
      80             :                         v1 = 2.0 * Random() - 1.0;
      81             :                         v2 = 2.0 * Random() - 1.0;
      82             :                         rsq = v1 * v1 + v2 * v2;
      83             :                 } while (rsq >= 1.0 || rsq == 0);
      84             : 
      85             :                 double fac = sqrt(-2.0 * log(rsq) / rsq);
      86             : 
      87             :                 // Perform Box-Muller transformation to get two normal deviates.
      88             :                 // Return one and save the other for next time.
      89             :                 ctx->unif = v1 * fac;
      90             :                 return v2 * fac;
      91             :         } else {
      92             :                 // A deviate is already available
      93             :                 double ret = ctx->unif;
      94             :                 ctx->unif = NAN;
      95             :                 return ret;
      96             :         }
      97             : }
      98             : 
      99           0 : int RandomRange(int min, int max)
     100             : {
     101             :         return (int)floor(Random() * (max - min + 1)) + min;
     102             : }
     103             : 
     104           0 : int RandomRangeNonUniform(int x, int min, int max)
     105             : {
     106             :         return (((RandomRange(0, x) | RandomRange(min, max))) %
     107             :                         (max - min + 1)) + min;
     108             : }
     109             : 
     110             : /**
     111             :  * Return a number in according to a Gamma Distribution of Integer Order ia,
     112             :  * a waiting time to the ia-th event in a Poisson process of unit mean.
     113             :  *
     114             :  * @author D. E. Knuth
     115             :  * @param ia Integer Order of the Gamma Distribution
     116             :  * @return A random number
     117             :  */
     118           1 : double Gamma(unsigned ia)
     119             : {
     120             :         if (unlikely(ia < 1)) {
     121             :                 log_log(LOG_WARN, "Gamma distribution must have a ia "
     122             :                                 "value >= 1. Defaulting to 1...");
     123             :                 ia = 1;
     124             :         }
     125             : 
     126             :         double x;
     127             : 
     128             :         if (ia < 6) {
     129             :                 // Use direct method, adding waiting times
     130             :                 x = 1.0;
     131             :                 while (ia--)
     132             :                         x *= 1 - Random();
     133             :                 x = -log(x);
     134             :         } else {
     135             :                 double am = ia - 1;
     136             :                 double v1, v2, e, y, s;
     137             :                 // Use rejection method
     138             :                 do {
     139             :                         do {
     140             :                                 do {
     141             :                                         v1 = Random();
     142             :                                         v2 = 2.0 * Random() - 1.0;
     143             :                                 } while (v1 * v1 + v2 * v2 > 1.0);
     144             : 
     145             :                                 y = v2 / v1;
     146             :                                 s = sqrt(2.0 * am + 1.0);
     147             :                                 x = s * y + am;
     148             :                         } while (x < 0.0);
     149             : 
     150             :                         e = (1.0 + y * y) * exp(am * log(x / am) - s * y);
     151             :                 } while (Random() > e);
     152             :         }
     153             : 
     154             :         return x;
     155             : }
     156             : 
     157             : /**
     158             :  * Return the waiting time to the next event in a Poisson process of unit mean.
     159             :  *
     160             :  * @return A random number
     161             :  */
     162           1 : double Poisson(void)
     163             : {
     164             :         return -log(1 - Random());
     165             : }
     166             : 
     167             : /**
     168             :  * Return a random sample from a Zipf distribution.
     169             :  * Based on the rejection method by Luc Devroye for sampling:
     170             :  * "Non-Uniform Random Variate Generation, page 550, Springer-Verlag, 1986
     171             :  *
     172             :  * @param skew The skew of the distribution
     173             :  * @param limit The largest sample to retrieve
     174             :  * @return A random number
     175             :  */
     176           1 : unsigned Zipf(double skew, unsigned limit)
     177             : {
     178             :         double b = pow(2., skew - 1.);
     179             :         double x, t;
     180             :         do {
     181             :                 x = floor(pow(Random(), -1. / skew - 1.));
     182             :                 t = pow(1. + 1. / x, skew - 1.);
     183             :         } while (x > limit || Random() * x * (t - 1.) * b > t * (b - 1.));
     184             :         return x;
     185             : }

Generated by: LCOV version 1.14