From 344960f7470d7b6e5cb0c0b1d7e751d47063a98c Mon Sep 17 00:00:00 2001
From: Marc Sunet <msunet@shellblade.net>
Date: Sat, 7 May 2022 08:09:10 -0700
Subject: Add random library.

---
 random/CMakeLists.txt              |  10 ++
 random/LICENSE                     |  60 ++++++++++++
 random/include/random/mt19937-64.h |  40 ++++++++
 random/include/random/random.h     |   3 +
 random/src/mt19937-64.c            | 183 +++++++++++++++++++++++++++++++++++++
 5 files changed, 296 insertions(+)
 create mode 100644 random/CMakeLists.txt
 create mode 100644 random/LICENSE
 create mode 100644 random/include/random/mt19937-64.h
 create mode 100644 random/include/random/random.h
 create mode 100644 random/src/mt19937-64.c

(limited to 'random')

diff --git a/random/CMakeLists.txt b/random/CMakeLists.txt
new file mode 100644
index 0000000..ec80b1d
--- /dev/null
+++ b/random/CMakeLists.txt
@@ -0,0 +1,10 @@
+cmake_minimum_required(VERSION 3.0)
+
+project(random)
+
+add_library(random
+  src/mt19937-64.c)
+
+target_include_directories(random PUBLIC include)
+
+target_compile_options(random PRIVATE -Wall -Wextra)
diff --git a/random/LICENSE b/random/LICENSE
new file mode 100644
index 0000000..867af1f
--- /dev/null
+++ b/random/LICENSE
@@ -0,0 +1,60 @@
+This library is licensed under the GNU AFFERO GENERAL PUBLIC LICENSE. The
+license text can be found in the top-level LICENSE file of this project.
+
+This library makes use of third-party software. The licenses for this
+third-party software are listed below.
+
+# mt19937-64.c
+
+A C-program for MT19937-64 (2004/9/29 version).
+Coded by Takuji Nishimura and Makoto Matsumoto.
+
+This is a 64-bit version of Mersenne Twister pseudorandom number
+generator.
+
+Before using, initialize the state by using init_genrand64(seed)
+or init_by_array64(init_key, key_length).
+
+Copyright (C) 2004, Makoto Matsumoto and Takuji Nishimura,
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+1. Redistributions of source code must retain the above copyright
+notice, this list of conditions and the following disclaimer.
+
+2. Redistributions in binary form must reproduce the above copyright
+notice, this list of conditions and the following disclaimer in the
+documentation and/or other materials provided with the distribution.
+
+3. The names of its contributors may not be used to endorse or promote
+products derived from this software without specific prior written
+permission.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+References:
+T. Nishimura, ``Tables of 64-bit Mersenne Twisters''
+ACM Transactions on Modeling and
+Computer Simulation 10. (2000) 348--357.
+M. Matsumoto and T. Nishimura,
+``Mersenne Twister: a 623-dimensionally equidistributed
+  uniform pseudorandom number generator''
+ACM Transactions on Modeling and
+Computer Simulation 8. (Jan. 1998) 3--30.
+
+Any feedback is very welcome.
+http://www.math.hiroshima-u.ac.jp/~m-mat/MT/emt.html
+email: m-mat @ math.sci.hiroshima-u.ac.jp (remove spaces)
diff --git a/random/include/random/mt19937-64.h b/random/include/random/mt19937-64.h
new file mode 100644
index 0000000..bd1125f
--- /dev/null
+++ b/random/include/random/mt19937-64.h
@@ -0,0 +1,40 @@
+#pragma once
+
+#include <stdint.h>
+
+#define MT19937_64_NN 312
+
+typedef struct mt19937_64 {
+  uint64_t mt[MT19937_64_NN];  // The array for the state vector.
+  int mti;                     // mti==NN+1 means mt[NN] is not initialized.
+} mt19937_64;
+
+/// Creates a default-initialized 64-bit Mersenne Twister PRNG.
+mt19937_64 mt19937_64_make();
+
+/// Initializes the PRNG with a seed.
+void mt19937_64_init(mt19937_64* rng, uint64_t seed);
+
+/// Initializes the PRNG with an array of values.
+/// |init_key| is the array for initializing keys.
+/// |key_length| is its length.
+void mt19937_64_init_by_array64(
+  mt19937_64* rng, uint64_t init_key[], uint64_t key_length);
+
+/// Generates a random number in the [0, 2^64-1]-interval.
+uint64_t mt19937_64_gen64u(mt19937_64* rng);
+
+/// Generates a random number in the [0, 2^63-1]-interval.
+int64_t mt19937_64_gen64i(mt19937_64* rng);
+
+/// Generates a random number in the [0,1]-real-interval.
+double mt19937_64_gen_real1(mt19937_64* rng);
+
+/// Generates a random number in the [0,1)-real-interval.
+double mt19937_64_gen_real2(mt19937_64* rng);
+
+/// Generates a random number in the (0,1)-real-interval.
+double mt19937_64_gen_real3(mt19937_64* rng);
+
+/// Generates a random number in the (-1,+1)-real-interval.
+double mt19937_64_gen_real4(mt19937_64* rng);
diff --git a/random/include/random/random.h b/random/include/random/random.h
new file mode 100644
index 0000000..5499f62
--- /dev/null
+++ b/random/include/random/random.h
@@ -0,0 +1,3 @@
+#pragma once
+
+#include <random/mt19937-64.h>
diff --git a/random/src/mt19937-64.c b/random/src/mt19937-64.c
new file mode 100644
index 0000000..b6f7be6
--- /dev/null
+++ b/random/src/mt19937-64.c
@@ -0,0 +1,183 @@
+// http://www.math.sci.hiroshima-u.ac.jp/m-mat/MT/VERSIONS/C-LANG/mt19937-64.c
+
+/*
+   A C-program for MT19937-64 (2004/9/29 version).
+   Coded by Takuji Nishimura and Makoto Matsumoto.
+
+   This is a 64-bit version of Mersenne Twister pseudorandom number
+   generator.
+
+   Before using, initialize the state by using init_genrand64(seed)
+   or init_by_array64(init_key, key_length).
+
+   Copyright (C) 2004, Makoto Matsumoto and Takuji Nishimura,
+   All rights reserved.
+
+   Redistribution and use in source and binary forms, with or without
+   modification, are permitted provided that the following conditions
+   are met:
+
+   1. Redistributions of source code must retain the above copyright
+    notice, this list of conditions and the following disclaimer.
+
+   2. Redistributions in binary form must reproduce the above copyright
+    notice, this list of conditions and the following disclaimer in the
+    documentation and/or other materials provided with the distribution.
+
+   3. The names of its contributors may not be used to endorse or promote
+    products derived from this software without specific prior written
+    permission.
+
+   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+   A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE COPYRIGHT OWNER OR
+   CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+   EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+   PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+   PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+   LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+   NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+   SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+   References:
+   T. Nishimura, ``Tables of 64-bit Mersenne Twisters''
+   ACM Transactions on Modeling and
+   Computer Simulation 10. (2000) 348--357.
+   M. Matsumoto and T. Nishimura,
+   ``Mersenne Twister: a 623-dimensionally equidistributed
+     uniform pseudorandom number generator''
+   ACM Transactions on Modeling and
+   Computer Simulation 8. (Jan. 1998) 3--30.
+
+   Any feedback is very welcome.
+   http://www.math.hiroshima-u.ac.jp/~m-mat/MT/emt.html
+   email: m-mat @ math.sci.hiroshima-u.ac.jp (remove spaces)
+*/
+
+/*
+Modifications:
+
+- Remove stdio.h and the main() function.
+- Replace 'unsigned long long' with 'uint64_t' (include stdint.h).
+- Remove the global state and instead store the generator's state in the new
+  mt19937_64 struct.
+- Naming and formatting.
+*/
+
+#include <random/mt19937-64.h>
+
+#include <assert.h>
+
+#define NN 312
+#define MM 156
+#define MATRIX_A 0xB5026F5AA96619E9ULL
+#define UM 0xFFFFFFFF80000000ULL /* Most significant 33 bits */
+#define LM 0x7FFFFFFFULL /* Least significant 31 bits */
+
+mt19937_64 mt19937_64_make() {
+  mt19937_64 rng;
+  rng.mti = NN+1;  // Not initialized.
+  return rng;
+}
+
+/* initializes mt[NN] with a seed */
+void mt19937_64_init(mt19937_64* rng, uint64_t seed) {
+  assert(rng);
+  rng->mt[0] = seed;
+  for (rng->mti = 1; rng->mti < NN; rng->mti++) {
+    rng->mt[rng->mti] =
+        (6364136223846793005ULL * (rng->mt[rng->mti - 1] ^ (rng->mt[rng->mti - 1] >> 62)) + rng->mti);
+  }
+}
+
+/* initialize by an array with array-length */
+/* init_key is the array for initializing keys */
+/* key_length is its length */
+void mt19937_64_init_by_array64(mt19937_64* rng, uint64_t init_key[], uint64_t key_length) {
+  assert(rng);
+  uint64_t i, j, k;
+  mt19937_64_init(rng, 19650218ULL);
+  i=1; j=0;
+  k = (NN>key_length ? NN : key_length);
+  for (; k; k--) {
+    rng->mt[i] = (rng->mt[i] ^ ((rng->mt[i-1] ^ (rng->mt[i-1] >> 62)) * 3935559000370003845ULL))
+      + init_key[j] + j; /* non linear */
+    i++; j++;
+    if (i>=NN) { rng->mt[0] = rng->mt[NN-1]; i=1; }
+    if (j>=key_length) j=0;
+  }
+  for (k=NN-1; k; k--) {
+    rng->mt[i] = (rng->mt[i] ^ ((rng->mt[i-1] ^ (rng->mt[i-1] >> 62)) * 2862933555777941757ULL))
+      - i; /* non linear */
+    i++;
+    if (i>=NN) { rng->mt[0] = rng->mt[NN-1]; i=1; }
+  }
+
+  rng->mt[0] = 1ULL << 63; /* MSB is 1; assuring non-zero initial array */
+}
+
+/* generates a random number on [0, 2^64-1]-interval */
+uint64_t mt19937_64_gen64u(mt19937_64* rng) {
+  assert(rng);
+  int i;
+  uint64_t x;
+  static uint64_t mag01[2]={0ULL, MATRIX_A};
+
+  if (rng->mti >= NN) { /* generate NN words at one time */
+
+    /* if mt19937_64_init() has not been called, */
+    /* a default initial seed is used   */
+    if (rng->mti == NN+1)
+      mt19937_64_init(rng, 5489ULL);
+
+    for (i=0;i<NN-MM;i++) {
+      x = (rng->mt[i]&UM)|(rng->mt[i+1]&LM);
+      rng->mt[i] = rng->mt[i+MM] ^ (x>>1) ^ mag01[(int)(x&1ULL)];
+    }
+    for (;i<NN-1;i++) {
+      x = (rng->mt[i]&UM)|(rng->mt[i+1]&LM);
+      rng->mt[i] = rng->mt[i+(MM-NN)] ^ (x>>1) ^ mag01[(int)(x&1ULL)];
+    }
+    x = (rng->mt[NN-1]&UM)|(rng->mt[0]&LM);
+    rng->mt[NN-1] = rng->mt[MM-1] ^ (x>>1) ^ mag01[(int)(x&1ULL)];
+
+    rng->mti = 0;
+  }
+
+  x = rng->mt[rng->mti++];
+
+  x ^= (x >> 29) & 0x5555555555555555ULL;
+  x ^= (x << 17) & 0x71D67FFFEDA60000ULL;
+  x ^= (x << 37) & 0xFFF7EEE000000000ULL;
+  x ^= (x >> 43);
+
+  return x;
+}
+
+/* generates a random number on [0, 2^63-1]-interval */
+int64_t mt19937_64_gen64i(mt19937_64* rng) {
+  return (int64_t)(mt19937_64_gen64u(rng) >> 1);
+}
+
+/* generates a random number on [0,1]-real-interval */
+double mt19937_64_gen_real1(mt19937_64* rng) {
+  return (mt19937_64_gen64u(rng) >> 11) * (1.0/9007199254740991.0);
+}
+
+/* generates a random number on [0,1)-real-interval */
+double mt19937_64_gen_real2(mt19937_64* rng) {
+  return (mt19937_64_gen64u(rng) >> 11) * (1.0/9007199254740992.0);
+}
+
+/* generates a random number on (0,1)-real-interval */
+double mt19937_64_gen_real3(mt19937_64* rng) {
+  return ((mt19937_64_gen64u(rng) >> 12) + 0.5) * (1.0/4503599627370496.0);
+}
+
+/* generates a random number on (-1,+1)-real-interval */
+double mt19937_64_gen_real4(mt19937_64* rng) {
+  const double x01 = mt19937_64_gen_real3(rng);  // (0,1) interval.
+  const double x11 = x01 * 2. - 1.;  // (-1, +1) interval.
+  return x11;
+}
-- 
cgit v1.2.3