From c3cd051095e25822f2859aeb663e995d1bfc9c7f Mon Sep 17 00:00:00 2001
From: Enzo De Carvalho Bittencourt <enzo.decarvalhobittencourt@ensiie.eu>
Date: Fri, 22 Sep 2023 17:23:56 +0200
Subject: [PATCH] added RNG + creating plots

---
 Random/.generators.py.swp                    | Bin 12288 -> 0 bytes
 Random/__pycache__/generators.cpython-36.pyc | Bin 0 -> 7548 bytes
 Random/generators.py                         | 165 ++++++++++++++++++-
 Random/graph.py                              |   0
 Random/main.py                               |  29 +++-
 5 files changed, 183 insertions(+), 11 deletions(-)
 delete mode 100644 Random/.generators.py.swp
 create mode 100644 Random/__pycache__/generators.cpython-36.pyc
 create mode 100644 Random/graph.py

diff --git a/Random/.generators.py.swp b/Random/.generators.py.swp
deleted file mode 100644
index af74f0d2fd905306d364547cccd8084cc04b07d5..0000000000000000000000000000000000000000
GIT binary patch
literal 0
HcmV?d00001

literal 12288
zcmeI2KW`H;7>6BZLJ=@Bn4Bsl(EI@g3Q}335S>&qw4!Tpb545b&KKEtDrJBH!OGIH
zAjAMde2Ox$u&^S*H(=odz|X$isXz;&Tcp?0le6Em{l0!K9je@BXT!hEueUl3?KES1
z&#Lm>r)9SLim`h_HH9*Xz4f;iMoCi%H5JWmu`Q0C`LNiq-5ad?ey_dm_x<*oP(c#6
zCsIi*(nOoqbm!<j=nfem1II9srQ_yum0i7Z+5M?|wF~_0nLEeWh?bB6GC&5%02v?y
zWPl8i0WvVJ2GVJTJwov(W(QcDT`Rv`XG6M>0Wv@a$N(8217v^<kO4A42FL&zAOmw~
zKm?3EKFL_SisJG6fARnS*9FGDfPL^5JOxjH0Ta*#*T6Zj0Dhce>^t}f_Q4DA9PEJy
zK!aQ0CRhRIK?Qt6-p}9zcmrO8T_C_+Fa$l|>YGEqR5BSL17v^<kO4A42FL&zAOmx2
zfX|wd(YSS=uW%z}z-%y(V>hVVTT8CnxPf!pd$t`|fu(|9EFzck&WJDOotW9_c029f
zjIP^lY{<59mk#$ZMPyNm*sO$df<R${*`aN2%?P0pbK@cuBa|nzVUtazt~Xl4VW`4%
zIIK6A4cj`(P=2&{iI0}JD9WnUYHsFgsHD)mo2ZG-q)I~(@$#i^E}}`I!*nZ8XxEG)
zVGLjG_Uri@;DapQl)7KM2L6jYEz?XZK1fnOo<=gp_A=;cooJWZ7Fv{H`$ncb-IC4>
zPsXlamcr}|+lm$ClS4`ycOSO%pILW883kN$<qpEfI*DE8wL!n!@?g$G9`8Rg{_!wS
dajx-Dh4|ih9^Vi;OftjsDZCVH-oNxb_7htp0!RP=

diff --git a/Random/__pycache__/generators.cpython-36.pyc b/Random/__pycache__/generators.cpython-36.pyc
new file mode 100644
index 0000000000000000000000000000000000000000..12d1299222c60aedbec5e87efed307976b0ef7b8
GIT binary patch
literal 7548
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
F{tNKC9yI^}

literal 0
HcmV?d00001

diff --git a/Random/generators.py b/Random/generators.py
index 3534ead..2d8a444 100644
--- a/Random/generators.py
+++ b/Random/generators.py
@@ -1,37 +1,188 @@
 ## Various Random Generators ##
+import random
+
 
 class RandomNumberGenerator:
     def __init__(self):
         return NotImplementedError
 
-    def random():
+    def random(self):
         """
         yield a number from the RNG
         """
         return NotImplementedError
-    
-    def seed():
+
+    def seed(self):
         """
         set the seed of the generator
         """
         return NotImplementedError
 
+    def randomNorm(self):
+        """
+        return random between 0 and 1
+        """
+        return NotImplementedError
+
+    def batchRandomNormalized(self, n):
+        """
+        return n normalized values
+        """
+        return [self.randomNorm() for i in range(n)]
+
 
 class LCG(RandomNumberGenerator):
     """
     Linear Congruential generator algorithm
     """
 
-    def __init__(self, m, c, a):
+    def __init__(self, a, c, m):
         super().__init__()
         self.m = m
         self.c = c
         self.a = a
-        self.x = 0 #default seed
+        self.x = 0  # default seed
+
+    def random(self):
+        self.x = (self.a * self.x + self.c) % self.m
+        return self.x
+
+    def seed(self, seed):
+        self.x = seed
+
+    def randomNorm(self):
+        return self.random() / (self.m + 1)
 
-    def random():
-        self.x = self.a * self.x + self.c % self.m
+
+class ParkMiller(LCG):
+    """
+    Park and Miller's LCG
+    """
+
+    def __init__(self):
+        super().__init__(16807, 0, 2147483647)
+
+
+class KnuthLewis(LCG):
+    """
+    Knuth and Lewis' LCG
+    """
+
+    def __init__(self):
+        super().__init__(1664525, 1013904223, 4294967296)
+
+
+class Marsaglia(LCG):
+    """
+    Marsaglia's LCG
+    """
+
+    def __init__(self):
+        super().__init__(69069, 0, 4294967296)
+
+
+class LavauxJenssens(LCG):
+    """
+    Lavaux And Jenssens' LCG
+    """
+
+    def __init__(self):
+        super().__init__(31167285, 1, 281474976710656)
+
+
+class Haynes(LCG):
+    """
+    Haynes' LCG
+    """
+
+    def __init__(self):
+        super().__init__(6364136223846793005, 1, 18446744073709552000)
 
 
+class LaggedFibonnaci(RandomNumberGenerator):
+    """
+    Lagged Fibonnaci generator algorithm
+    """
+
+    def __init__(self, l, k, m):
+        self.l = l
+        self.k = k
+        self.m = m
+        self.ParkMiller = ParkMiller()
+        self.values = []
+
+    def seed(self, seed):
+        self.ParkMiller.seed(seed)
+        self.values = [self.ParkMiller.random() for i in range(max(self.l, self.k))]
+
+    def random(self):
+        # init values if non-existents
+        if not (self.values):
+            self.values = [self.ParkMiller.random() for i in range(max(self.l, self.k))]
+        val = (self.values[-self.l] + self.values[-self.k]) % self.m
+        self.values.append(val)
+        return self.values[-1]
+
+    def randomNorm(self):
+        return random() / (self.m + 1)
+
+
+class MitchelMoore(LaggedFibonnaci):
+    """
+    Mitchel and Moore's Lagged Fibonnaci
+    we use m = 2^32
+    """
+
+    def __init__(self):
+        super().__init__(24, 55, 4294967296)
+
+
+class MersenneTwister(RandomNumberGenerator):
+    """
+    MersenneTwister algorithm (native random.random())
+    """
+
+    def __init__(self):
+        super().__init__()
+
+    def seed(self, seed):
+        random.seed(seed)
+
+    def randomNorm(self):
+        return random.random()
+
+    def random(self):
+        return self.randomNorm()
+
+
+class CNS(RandomNumberGenerator):
+    """
+    Cryptography Network Security
+    """
+
+    def __init__(self, x0, M):
+        super().__init__()
+        self.M = M
+        self.x = x0  # must verify pgcd(M,x0) = 1
+
     def seed(self, seed):
         self.x = seed
+
+    def random(self):
+        self.x = pow(self.x, 2) % self.M
+        return self.x
+
+    def randomNorm(self):
+        return self.random() / (self.M + 1)
+
+
+class BlumBlumShub(CNS):
+    """
+    Blum Blum Shub
+    """
+
+    def __init__(self):
+        super().__init__(7817, 56923661)
+
+    def seed(self, seed):
+        return  # do nothing
diff --git a/Random/graph.py b/Random/graph.py
new file mode 100644
index 0000000..e69de29
diff --git a/Random/main.py b/Random/main.py
index 3ab482e..3fc8978 100644
--- a/Random/main.py
+++ b/Random/main.py
@@ -1,7 +1,28 @@
-import generators
+from generators import *
+from datetime import datetime
+import matplotlib.pyplot as plt
+import numpy as np
+
 
 if __name__=="__main__":
-    LCG = generators.LCG(5, 1, 1)
-    LCG.seed(0)
-    print(LCG.random())
 
+    generators = [ParkMiller(), KnuthLewis(), Marsaglia()
+                  , LavauxJenssens(), Haynes(), MitchelMoore()
+                  , MersenneTwister(), BlumBlumShub()]
+    
+    seed = datetime.now().timestamp()
+    N = 1000
+    RESOLUTION = 100
+
+    for e in generators:
+        e.seed(seed)
+        res = e.batchRandomNormalized(N)
+        
+        #matplotlib prep
+        #see https://matplotlib.org/stable/gallery/statistics/histogram_features.html#sphx-glr-gallery-statistics-histogram-features-py
+        fig, ax = plt.subplots()
+        n, bins, patches = ax.hist(res, RESOLUTION, density=True)
+        ax.set_xlabel('Value')
+        ax.set_ylabel('Probability density')
+        ax.set_title(type(e).__name__)
+        plt.savefig(type(e).__name__+'.png')
-- 
GitLab