Skip to content

Commit d66a4c6

Browse files
authored
Merge pull request #128 from schmouk/dev
Dev --> Py3-11
2 parents f09ca47 + e6f4fd7 commit d66a4c6

170 files changed

Lines changed: 23526 additions & 1475 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

PyRandLib/README.md

Lines changed: 0 additions & 686 deletions
This file was deleted.

PyRandLib/__init__.py

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,21 +6,39 @@
66
Copyright (c) 2016-2025 Philippe Schmouker, schmouk (at) gmail.com
77
"""
88

9+
from .basecwg import BaseCWG
910
from .baselcg import BaseLCG
1011
from .baselfib64 import BaseLFib64
12+
from .basemelg import BaseMELG
1113
from .basemrg import BaseMRG
1214
from .baserandom import BaseRandom
15+
from .basesquares import BaseSquares
1316
from .basewell import BaseWELL
17+
from .basexoroshiro import BaseXoroshiro
18+
from .cwg64 import Cwg64
19+
from .cwg128_64 import Cwg128_64
20+
from .cwg128 import Cwg128
1421
from .fastrand32 import FastRand32
1522
from .fastrand63 import FastRand63
1623
from .lfib78 import LFib78
1724
from .lfib116 import LFib116
1825
from .lfib668 import LFib668
1926
from .lfib1340 import LFib1340
20-
from .mrgrand287 import MRGRand287
21-
from .mrgrand1457 import MRGRand1457
22-
from .mrgrand49507 import MRGRand49507
27+
from .melg607 import Melg607
28+
from .melg19937 import Melg19937
29+
from .melg44497 import Melg44497
30+
from .mrg287 import Mrg287
31+
from .mrg1457 import Mrg1457
32+
from .mrg49507 import Mrg49507
33+
from .pcg64_32 import Pcg64_32
34+
from .pcg128_64 import Pcg128_64
35+
from .pcg1024_32 import Pcg1024_32
36+
from .squares32 import Squares32
37+
from .squares64 import Squares64
2338
from .well512a import Well512a
2439
from .well1024a import Well1024a
2540
from .well19937c import Well19937c
2641
from .well44497b import Well44497b
42+
from .xoroshiro256 import Xoroshiro256
43+
from .xoroshiro512 import Xoroshiro512
44+
from .xoroshiro1024 import Xoroshiro1024

PyRandLib/annotation_types.py

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,9 +23,11 @@
2323
#=============================================================================
2424
from typing import List, Tuple, Union
2525

26-
Numerical = Union[ int, float ]
27-
StateType = Union[ Tuple[Numerical], List[Numerical], Tuple[List[Numerical], int], Tuple[Tuple[Numerical], int] ]
28-
SeedStateType = Union[ Numerical, StateType ]
26+
Numerical = Union[ int, float ]
27+
StatesList = Union[ Tuple[int], List[int] ]
28+
StatesListAndExt = Tuple[ StatesList, int ]
29+
StateType = Union[ StatesList, StatesListAndExt ]
30+
SeedStateType = Union[ Numerical, StateType ]
2931

3032

3133
#===== end of PyRandLib.annotation_types ===============================

PyRandLib/basecwg.py

Lines changed: 113 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,113 @@
1+
"""
2+
Copyright (c) 2025 Philippe Schmouker, schmouk (at) gmail.com
3+
4+
Permission is hereby granted, free of charge, to any person obtaining a copy
5+
of this software and associated documentation files (the "Software"), to deal
6+
in the Software without restriction, including without limitation the rights
7+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
8+
copies of the Software, and to permit persons to whom the Software is
9+
furnished to do so, subject to the following conditions:
10+
11+
The above copyright notice and this permission notice shall be included in all
12+
copies or substantial portions of the Software.
13+
14+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
15+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
16+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
17+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
18+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
19+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
20+
SOFTWARE.
21+
"""
22+
23+
#=============================================================================
24+
from .baserandom import BaseRandom
25+
from .annotation_types import SeedStateType, StatesListAndExt
26+
27+
28+
#=============================================================================
29+
class BaseCWG( BaseRandom ):
30+
"""Definition of the base class for all Collatz-Weyl pseudo-random Generators.
31+
32+
This module is part of library PyRandLib.
33+
34+
Copyright (c) 2025 Philippe Schmouker
35+
36+
CWG models are chaotic generators that are combined with Weyl sequences to
37+
eliminate the risk of short cycles. They have a large period, a uniform
38+
distribution, and the ability to generate multiple independent streams by
39+
changing their internal parameters (Weyl increment). CWGs owe their
40+
exceptional quality to the arithmetical dynamics of noninvertible,
41+
generalized, Collatz mappings based on the wellknown Collatz conjecture.
42+
There is no jump function, but each odd number of the Weyl increment
43+
initiates a new unique period, which enables quick initialization of
44+
independent streams (this text is extracted from [8], see README.md).
45+
46+
The internal implementation of the CWG algorithm varies according to its
47+
implemented version. See implementation classes to get their formal
48+
description.
49+
50+
See Cwg64 for a minimum 2^70 (i.e. about 1.18e+21) period CW-Generator
51+
with low computation time, medium period, 64- bits output values and very
52+
good randomness characteristics.
53+
See Cwg128_64 for a minimum 2^71 (i.e. about 2.36e+21) period CW-Generator
54+
with very low computation time, medium period, 64-bits output values and
55+
very good randomness characteristics.
56+
See Cwg128 for a minimum 2^135 (i.e. about 4.36e+40) period CW-generator
57+
with very low computation time, medium period, 64- bits output values and
58+
very good randomness characteristics.
59+
60+
Furthermore this class is callable:
61+
rand = BaseCWG() # Caution: this is just used as illustrative. This base class cannot be instantiated
62+
print( rand() ) # prints a pseudo-random value within [0.0, 1.0)
63+
print( rand(a) ) # prints a pseudo-random value within [0, a) or [0.0, a) depending on the type of a
64+
print( rand(a, n) ) # prints a list of n pseudo-random values each within [0, a)
65+
66+
Reminder:
67+
We give you here below a copy of the table of tests for the CWGs that have
68+
been implemented in PyRandLib, as presented in paper [8] - see file README.md.
69+
70+
| PyRandLib class | [8] generator name | Memory Usage | Period | time-32bits | time-64 bits | SmallCrush fails | Crush fails | BigCrush fails |
71+
| --------------- | ------------------ | ------------- | -------- | ----------- | ------------ | ---------------- | ----------- | -------------- |
72+
| Cwg64 | CWG64 | 8 x 4-bytes | >= 2^70 | n.a. | n.a. | 0 | 0 | 0 |
73+
| Cwg128_64 | CWG128_64 | 10 x 4-bytes | >= 2^71 | n.a. | n.a. | 0 | 0 | 0 |_
74+
| Cwg128 | CWG128 | 16 x 4-bytes | >= 2^135 | n.a. | n.a. | 0 | 0 | 0 |
75+
76+
* _small crush_ is a small set of simple tests that quickly tests some of
77+
the expected characteristics for a pretty good PRNG;
78+
* _crush_ is a bigger set of tests that test more deeply expected random
79+
characteristics;
80+
* _big crush_ is the ultimate set of difficult tests that any GOOD PRNG
81+
should definitively pass.
82+
"""
83+
84+
#-------------------------------------------------------------------------
85+
def __init__(self, _seedState: SeedStateType = None) -> None:
86+
"""Constructor.
87+
88+
Should _seedState be None then the local time is used as a seed (with
89+
its shuffled value).
90+
Notice: method setstate() is not implemented in base class BaseRandom.
91+
So, it must be implemented in classes inheriting BaseLCG and it must
92+
initialize attribute self._state.
93+
"""
94+
super().__init__( _seedState ) # this internally calls 'setstate()' which
95+
# MUST be implemented in inheriting classes
96+
97+
98+
#-------------------------------------------------------------------------
99+
def getstate(self) -> StatesListAndExt:
100+
"""Returns an object capturing the current internal state of the generator.
101+
102+
This object can be passed to setstate() to restore the state.
103+
For CWG, this state is defined by a list of control values
104+
(a, weyl and s - or a list of 4 coeffs) and an internal state
105+
value, which are used in methods 'next() and 'setstate() of
106+
every inheriting class.
107+
108+
All inheriting classes MUST IMPLEMENT this method.
109+
"""
110+
return (self._a, self._weyl, self._s, self._state)
111+
112+
113+
#===== end of module basecwg.py ========================================

PyRandLib/baselcg.py

Lines changed: 31 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
"""
2222

2323
#=============================================================================
24-
from .baserandom import BaseRandom
24+
from .baserandom import BaseRandom
25+
from .annotation_types import Numerical
2526

2627

2728
#=============================================================================
@@ -37,12 +38,12 @@ class BaseLCG( BaseRandom ):
3738
3839
x(i-1): x(i) = (a*x(i-1) + c) mod m
3940
40-
Results are nevertheless considered to be poor as stated in the
41-
evaluation done by Pierre L'Ecuyer and Richard Simard (Universite de
42-
Montreal) in 'TestU01: A C Library for Empirical Testing of Random Number
43-
Generators - ACM Transactions on Mathematical Software, vol.33 n.4,
44-
pp.22-40, August 2007'. It is not recommended to use such pseudo-random
45-
numbers generators for serious simulation applications.
41+
Results are nevertheless considered to be poor as stated in the evaluation
42+
done by Pierre L'Ecuyer and Richard Simard (Universite de Montreal) in
43+
'TestU01: A C Library for Empirical Testing of Random Number Generators -
44+
ACM Transactions on Mathematical Software, vol.33 n.4, pp.22-40, August
45+
2007'. It is not recommended to use such pseudo-random numbers generators
46+
for serious simulation applications.
4647
4748
See FastRand32 for a 2^32 (i.e. 4.3e+9) period LC-Generator with very low
4849
computation time but shorter period and worse randomness characteristics
@@ -52,73 +53,52 @@ class BaseLCG( BaseRandom ):
5253
characteristics than for FastRand32.
5354
5455
Furthermore this class is callable:
55-
rand = BaseLCG()
56-
print( rand() ) # prints a pseudo-random value within [0.0, 1.0)
57-
print( rand(a) ) # prints a pseudo-random value within [0.0, a)
58-
print( rand(a,b) ) # prints a pseudo-random value within [a , b)
56+
rand = BaseLCG() # Caution: this is just used as illustrative. This base class cannot be instantiated
57+
print( rand() ) # prints a pseudo-random value within [0.0, 1.0)
58+
print( rand(a) ) # prints a pseudo-random value within [0, a) or [0.0, a) depending on the type of a
59+
print( rand(a, n) ) # prints a list of n pseudo-random values each within [0, a)
5960
6061
Reminder:
6162
We give you here below a copy of the table of tests for the LCGs that have
6263
been implemented in PyRandLib, as provided in paper "TestU01, ..." - see
6364
file README.md.
6465
65-
| PyRabndLib class | TU01 generator name | Memory Usage | Period | time-32bits | time-64 bits | SmallCrush fails | Crush fails | BigCrush fails |
66-
| ---------------- | ---------------------------------- | --------------- | ------- | ----------- | ------------ | ---------------- | ----------- | -------------- |
67-
| FastRand32 | LCG(2^32, 69069, 1) | 1 x 4-bytes | 2^32 | 3.20 | 0.67 | 11 | 106 | *too many* |
68-
| FastRand63 | LCG(2^63, 9219741426499971445, 1) | 2 x 4-bytes | 2^63 | 4.20 | 0.75 | 0 | 5 | 7 |
66+
| PyRandLib class | TU01 generator name | Memory Usage | Period | time-32bits | time-64 bits | SmallCrush fails | Crush fails | BigCrush fails |
67+
| --------------- | ---------------------------------- | --------------- | ------- | ----------- | ------------ | ---------------- | ----------- | -------------- |
68+
| FastRand32 | LCG(2^32, 69069, 1) | 1 x 4-bytes | 2^32 | 3.20 | 0.67 | 11 | 106 | *too many* |
69+
| FastRand63 | LCG(2^63, 9219741426499971445, 1) | 2 x 4-bytes | 2^63 | 4.20 | 0.75 | 0 | 5 | 7 |
6970
7071
* _small crush_ is a small set of simple tests that quickly tests some of
71-
the expected characteristics for a pretty good PRG;
72+
the expected characteristics for a pretty good PRNG;
7273
* _crush_ is a bigger set of tests that test more deeply expected random
7374
characteristics;
74-
* _big crush_ is the ultimate set of difficult tests that any GOOD PRG
75+
* _big crush_ is the ultimate set of difficult tests that any GOOD PRNG
7576
should definitively pass.
7677
"""
7778

78-
#------------------------------------------------------------------------=
79-
def __init__(self, _seedState: int = None) -> None:
79+
#-------------------------------------------------------------------------
80+
def __init__(self, _seedState: Numerical = None) -> None:
8081
"""Constructor.
8182
82-
Should inSeed be None or not an integer then the local
83-
time is used (with its shuffled value) as a seed.
83+
Should _seedState be None then the local time is used as a seed (with
84+
its shuffled value).
85+
Notice: method setstate() is not implemented in base class BaseRandom.
86+
So, it must be implemented in classes inheriting BaseLCG and it must
87+
initialize attribute self._state.
8488
"""
85-
super().__init__( _seedState ) # this call creates attribute self._value and sets it
89+
super().__init__( _seedState ) # this internally calls 'setstate()' which
90+
# MUST be implemented in inheriting classes
8691

8792

88-
#------------------------------------------------------------------------=
89-
def random(self) -> float:
90-
"""This is the core of the pseudo-random generator.
91-
92-
Returned values are within [0.0, 1.0).
93-
Inheriting classes HAVE TO IMPLEMENT this method - see FastRand32
94-
for an example. It should use and initialize attribute self._value.
95-
"""
96-
raise NotImplementedError()
97-
98-
99-
#------------------------------------------------------------------------=
93+
#-------------------------------------------------------------------------
10094
def getstate(self) -> int:
10195
"""Returns an object capturing the current internal state of the generator.
10296
10397
This object can be passed to setstate() to restore the state.
104-
For LCG, the state is defined with a single integer, 'self._value',
105-
which has to be used in methods 'random() and 'setstate() of every
98+
For LCG, the state is defined with a single integer, 'self._state',
99+
which has to be used in methods 'next() and 'setstate() of every
106100
inheriting class.
107101
"""
108-
return self._value
109-
110-
111-
#------------------------------------------------------------------------=
112-
def setstate(self, _state: int) -> None:
113-
"""Restores the internal state of the generator.
114-
115-
_state should have been obtained from a previous call to getstate(),
116-
and setstate() restores the internal state of the generator to what
117-
it was at the time setstate() was called.
118-
Inheriting classes HAVE TO IMPLEMENT this method - see FastRand32
119-
for an example. It should initialize attribute self._value.
120-
"""
121-
raise NotImplementedError()
122-
102+
return self._state
123103

124104
#===== end of module baselcg.py ========================================

0 commit comments

Comments
 (0)