Skip to content

Commit

Permalink
Merge pull request #2793 from verilog-to-routing/temp_rand_remove_static
Browse files Browse the repository at this point in the history
Random number generation classes
  • Loading branch information
vaughnbetz authored Nov 5, 2024
2 parents 30b4927 + b83c603 commit 7a2cf8d
Show file tree
Hide file tree
Showing 45 changed files with 705 additions and 502 deletions.
96 changes: 43 additions & 53 deletions libs/libvtrutil/src/specrand.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,32 +52,15 @@

#include "specrand.h"

/* Period parameters */
#define N 624
#define M 397
#define MATRIX_A 0x9908b0dfUL /* constant vector a */
#define UPPER_MASK 0x80000000UL /* most significant w-r bits */
#define LOWER_MASK 0x7fffffffUL /* least significant r bits */

static unsigned long mt[N]; /* the array for the state vector */
static int mti = N + 1; /* mti==N+1 means mt[N] is not initialized */

void spec_srand(int seed) {
spec_init_genrand((unsigned long)seed);
double SpecRandomNumberGenerator::spec_rand_() {
return spec_genrand_int32_() * (1.0 / 4294967296.0);
}

/* Just a copy of spec_genrand_real2() */
double spec_rand() {
return spec_genrand_int32() * (1.0 / 4294967296.0);
long SpecRandomNumberGenerator::spec_lrand48_() {
return (long)(spec_genrand_int32_() >> 1);
}

/* Just a copy of spec_genrand_int31() */
long spec_lrand48() {
return (long)(spec_genrand_int32() >> 1);
}

/* initializes mt[N] with a seed */
void spec_init_genrand(unsigned long s) {
void SpecRandomNumberGenerator::spec_init_genrand_(unsigned long s) {
mt[0] = s & 0xffffffffUL;
for (mti = 1; mti < N; mti++) {
mt[mti] = (1812433253UL * (mt[mti - 1] ^ (mt[mti - 1] >> 30)) + mti);
Expand All @@ -90,16 +73,11 @@ void spec_init_genrand(unsigned long s) {
}
}

/* initialize by an array with array-length */
/* init_key is the array for initializing keys */
/* key_length is its length */
/* slight change for C++, 2004/2/26 */
void spec_init_by_array(unsigned long init_key[], int key_length) {
int i, j, k;
spec_init_genrand(19650218UL);
i = 1;
j = 0;
k = (N > key_length ? N : key_length);
void SpecRandomNumberGenerator::spec_init_by_array_(const unsigned long init_key[], size_t key_length) {
spec_init_genrand_(19650218UL);
size_t i = 1;
size_t j = 0;
size_t k = (N > key_length ? N : key_length);
for (; k; k--) {
mt[i] = (mt[i] ^ ((mt[i - 1] ^ (mt[i - 1] >> 30)) * 1664525UL))
+ init_key[j] + j; /* non linear */
Expand Down Expand Up @@ -127,22 +105,21 @@ void spec_init_by_array(unsigned long init_key[], int key_length) {
}

/* generates a random number on [0,0xffffffff]-interval */
unsigned long spec_genrand_int32() {
unsigned long SpecRandomNumberGenerator::spec_genrand_int32_() {
unsigned long y;
static unsigned long mag01[2] = {0x0UL, MATRIX_A};
/* mag01[x] = x * MATRIX_A for x=0,1 */

if (mti >= N) { /* generate N words at one time */
int kk;

if (mti == N + 1) /* if init_genrand() has not been called, */
spec_init_genrand(5489UL); /* a default initial seed is used */
spec_init_genrand_(5489UL); /* a default initial seed is used */

for (kk = 0; kk < N - M; kk++) {
for (size_t kk = 0; kk < N - M; kk++) {
y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
mt[kk] = mt[kk + M] ^ (y >> 1) ^ mag01[y & 0x1UL];
}
for (; kk < N - 1; kk++) {
for (size_t kk; kk < N - 1; kk++) {
y = (mt[kk] & UPPER_MASK) | (mt[kk + 1] & LOWER_MASK);
mt[kk] = mt[kk + (M - N)] ^ (y >> 1) ^ mag01[y & 0x1UL];
}
Expand All @@ -163,32 +140,45 @@ unsigned long spec_genrand_int32() {
return y;
}

/* generates a random number on [0,0x7fffffff]-interval */
long spec_genrand_int31() {
return (long)(spec_genrand_int32() >> 1);
long SpecRandomNumberGenerator::spec_genrand_int31_() {
return (long)(spec_genrand_int32_() >> 1);
}

/* generates a random number on [0,1]-real-interval */
double spec_genrand_real1() {
return spec_genrand_int32() * (1.0 / 4294967295.0);
double SpecRandomNumberGenerator::spec_genrand_real1_() {
return spec_genrand_int32_() * (1.0 / 4294967295.0);
/* divided by 2^32-1 */
}

/* generates a random number on [0,1)-real-interval */
double spec_genrand_real2() {
return spec_genrand_int32() * (1.0 / 4294967296.0);
double SpecRandomNumberGenerator::spec_genrand_real2_() {
return spec_genrand_int32_() * (1.0 / 4294967296.0);
/* divided by 2^32 */
}

/* generates a random number on (0,1)-real-interval */
double spec_genrand_real3() {
return (((double)spec_genrand_int32()) + 0.5) * (1.0 / 4294967296.0);
double SpecRandomNumberGenerator::spec_genrand_real3_() {
return (((double)spec_genrand_int32_()) + 0.5) * (1.0 / 4294967296.0);
/* divided by 2^32 */
}

/* generates a random number on [0,1) with 53-bit resolution*/
double spec_genrand_res53() {
unsigned long a = spec_genrand_int32() >> 5, b = spec_genrand_int32() >> 6;
double SpecRandomNumberGenerator::spec_genrand_res53_() {
unsigned long a = spec_genrand_int32_() >> 5, b = spec_genrand_int32_() >> 6;
return (a * 67108864.0 + b) * (1.0 / 9007199254740992.0);
}
/* These real versions are due to Isaku Wada, 2002/01/09 added */

void SpecRandomNumberGenerator::srandom(int seed) {
spec_init_genrand_((unsigned long)seed);
}

int SpecRandomNumberGenerator::irand(int imax) {
return (int)(spec_genrand_int31_() % (imax + 1));
}

float SpecRandomNumberGenerator::frand() {
return (float)spec_genrand_real2_();
}

SpecRandomNumberGenerator::SpecRandomNumberGenerator(int seed) {
spec_init_genrand_((unsigned long)seed);
}

SpecRandomNumberGenerator::SpecRandomNumberGenerator()
: SpecRandomNumberGenerator(0) {}
78 changes: 56 additions & 22 deletions libs/libvtrutil/src/specrand.h
Original file line number Diff line number Diff line change
Expand Up @@ -52,35 +52,69 @@
/* Slightly modified for use in SPEC CPU by Cloyce D. Spradling (5 Nov 2009)
*/

void spec_srand(int seed);
double spec_rand();
long spec_lrand48();
#include "vtr_random.h"

/* initializes mt[N] with a seed */
void spec_init_genrand(unsigned long s);
class SpecRandomNumberGenerator : public vtr::RandomNumberGeneratorInterface {
public:
SpecRandomNumberGenerator(const SpecRandomNumberGenerator&) = delete;
SpecRandomNumberGenerator& operator=(SpecRandomNumberGenerator& other) = delete;

/* initialize by an array with array-length */
/* init_key is the array for initializing keys */
/* key_length is its length */
/* slight change for C++, 2004/2/26 */
void spec_init_by_array(unsigned long init_key[], int key_length);
SpecRandomNumberGenerator();
explicit SpecRandomNumberGenerator(int seed);

/* generates a random number on [0,0xffffffff]-interval */
unsigned long spec_genrand_int32();
virtual void srandom(int seed) override;
virtual int irand(int imax) override;
virtual float frand() override;

/* generates a random number on [0,0x7fffffff]-interval */
long spec_genrand_int31();
private:
/// @brief initializes mt[N] with a seed
void spec_init_genrand_(unsigned long s);

/* generates a random number on [0,1]-real-interval */
double spec_genrand_real1();
/**
* @brief initialize by an array with array-length
* @param init_key the array for initializing keys
* @param key_length the length of array
*/
void spec_init_by_array_(const unsigned long init_key[], size_t key_length);

/* generates a random number on [0,1)-real-interval */
double spec_genrand_real2();
/// @brief generates a random number on [0,0xffffffff]-interval
unsigned long spec_genrand_int32_();

/* generates a random number on (0,1)-real-interval */
double spec_genrand_real3();
/// @brief Just a copy of spec_genrand_real2()
double spec_rand_();
/// @brief Just a copy of spec_genrand_int31()
long spec_lrand48_();

/* generates a random number on [0,1) with 53-bit resolution*/
double spec_genrand_res53();
/// @brief generates a random number on [0,0x7fffffff]-interval */
long spec_genrand_int31_();

/// @brief generates a random number on [0,1]-real-interval
double spec_genrand_real1_();

/// @brief generates a random number on [0,1)-real-interval
double spec_genrand_real2_();

/// @brief generates a random number on (0,1)-real-interval
double spec_genrand_real3_();

/// @brief generates a random number on [0,1) with 53-bit resolution
double spec_genrand_res53_();

private:
/// Period parameters
static constexpr size_t M = 397;
static constexpr size_t N = 624;
/// constant vector a
static constexpr unsigned long MATRIX_A = 0x9908b0dfUL;
/// most significant w-r bits
static constexpr unsigned long UPPER_MASK = 0x80000000UL;
/// least significant r bits
static constexpr unsigned long LOWER_MASK = 0x7fffffffUL;
/// mti==N+1 means mt[N] is not initialized
size_t mti = N + 1;
/// the array for the state vector
unsigned long mt[N];

};

#endif
102 changes: 39 additions & 63 deletions libs/libvtrutil/src/vtr_random.cpp
Original file line number Diff line number Diff line change
@@ -1,91 +1,67 @@
#include <cstddef>

#include "vtr_random.h"
#include "specrand.h"
#include "vtr_util.h"
#include "vtr_error.h"
#include "specrand.h"

#define CHECK_RAND

namespace vtr {
/* Portable random number generator defined below. Taken from ANSI C by *
* K & R. Not a great generator, but fast, and good enough for my needs. */

constexpr size_t IA = 1103515245u;
constexpr size_t IC = 12345u;
constexpr size_t IM = 2147483648u;

static RandState random_state = 0;

/**
* @brief The pseudo-random number generator is initialized using the argument passed as seed.
*/
void srandom(int seed) {
random_state = (unsigned int)seed;
#ifdef SPEC_CPU
/* SPEC CPU requires a different random number generator */
spec_init_genrand((unsigned long)seed);
#endif
RandomNumberGenerator::RandomNumberGenerator(int seed) {
random_state_ = (unsigned int)seed;
}

/* returns the random_state value */
RandState get_random_state() {
return random_state;
RandomNumberGenerator::RandomNumberGenerator()
: RandomNumberGenerator(0) {}

void RandomNumberGenerator::srandom(int seed) {
random_state_ = (unsigned int)seed;
}

int irand(int imax, RandState& state) {
#ifdef SPEC_CPU
/* SPEC CPU requires a different random number generator */
return (int)(spec_genrand_int31() % (imax + 1));
#else
/* Creates a random integer between 0 and imax, inclusive. i.e. [0..imax] */
int RandomNumberGenerator::irand(int imax) {
// Creates a random integer between 0 and imax, inclusive. i.e. [0..imax]
int ival;

/* state = (state * IA + IC) % IM; */
state = state * IA + IC; /* Use overflow to wrap */
ival = state & (IM - 1); /* Modulus */
// state = (state * IA + IC) % IM;
random_state_ = random_state_ * IA + IC; // Use overflow to wrap
ival = random_state_ & (IM - 1); // Modulus
ival = (int)((float)ival * (float)(imax + 0.999) / (float)IM);

# ifdef CHECK_RAND
if ((ival < 0) || (ival > imax)) {
if (ival == imax + 1) {
/* Due to random floating point rounding, sometimes above calculation gives number greater than ival by 1 */
ival = imax;
} else {
throw VtrError(string_fmt("Bad value in my_irand, imax = %d ival = %d", imax, ival), __FILE__, __LINE__);
if constexpr (CHECK_RAND_CONSTEXPR) {
if ((ival < 0) || (ival > imax)) {
if (ival == imax + 1) {
// Due to random floating point rounding, sometimes above calculation gives number greater than ival by 1
ival = imax;
} else {
throw VtrError(string_fmt("Bad value in my_irand, imax = %d ival = %d", imax, ival), __FILE__, __LINE__);
}
}
}
# endif

return ival;
#endif
}

int irand(int imax) {
return irand(imax, random_state);
}
float RandomNumberGenerator::frand() {
random_state_ = random_state_ * IA + IC; /* Use overflow to wrap */
int ival = random_state_ & (IM - 1); /* Modulus */
float fval = (float)ival / (float)IM;

float frand() {
/* Creates a random float between 0 and 1. i.e. [0..1). */
#ifdef SPEC_CPU
/* SPEC CPU requires a different random number generator */
return (float)spec_genrand_real2();
#else
float fval;
int ival;
if constexpr (CHECK_RAND_CONSTEXPR) {
if (fval < 0 || fval > 1.) {
throw VtrError(string_fmt("Bad value in my_frand, fval = %g", fval), __FILE__, __LINE__);
}
}

random_state = random_state * IA + IC; /* Use overflow to wrap */
ival = random_state & (IM - 1); /* Modulus */
fval = (float)ival / (float)IM;
return fval;
}

# ifdef CHECK_RAND
if ((fval < 0) || (fval > 1.)) {
throw VtrError(string_fmt("Bad value in my_frand, fval = %g", fval), __FILE__, __LINE__);
RngContainer::RngContainer(int seed) {
if constexpr (SPEC_CPU_CONSTEXPR) {
rng_ = std::make_unique<SpecRandomNumberGenerator>(seed);
} else {
rng_ = std::make_unique<vtr::RandomNumberGenerator>(seed);
}
# endif

return (fval);
#endif
}

RngContainer::RngContainer()
: RngContainer(0) {}
} // namespace vtr
Loading

0 comments on commit 7a2cf8d

Please sign in to comment.