Skip to content

Commit 536e8f0

Browse files
authored
Merge pull request #129 from schmouk/py3-11
Py3 11 --> Dev
2 parents 5c18035 + f68489e commit 536e8f0

File tree

213 files changed

+31099
-1646
lines changed

Some content is hidden

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

213 files changed

+31099
-1646
lines changed

LICENSE

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2016-2022 Philippe Schmouker, schmouk (at) gmail.com.
3+
Copyright (c) 2016-2025 Philippe Schmouker, schmouk (at) gmail.com.
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

PyRandLib/README.md

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

PyRandLib/__init__.py

Lines changed: 27 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,19 +3,42 @@
33
It is provided under MIT License.
44
Please see files README.md and LICENSE.
55
6-
Copyright (c) 2016-2022 Philippe Schmouker, schmouk (at) gmail.com
6+
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
16+
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
1321
from .fastrand32 import FastRand32
1422
from .fastrand63 import FastRand63
1523
from .lfib78 import LFib78
1624
from .lfib116 import LFib116
1725
from .lfib668 import LFib668
1826
from .lfib1340 import LFib1340
19-
from .mrgrand287 import MRGRand287
20-
from .mrgrand1457 import MRGRand1457
21-
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
38+
from .well512a import Well512a
39+
from .well1024a import Well1024a
40+
from .well19937c import Well19937c
41+
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: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
"""
2+
Copyright (c) 2021-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 typing import List, Tuple, Union
25+
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 ]
31+
32+
33+
#===== end of PyRandLib.annotation_types ===============================
34+
35+
# type: ignore (this comment line is just to avoid boring pylance related error checking)

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: 33 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
1-
#!/usr/bin/env python
2-
# -*- coding: utf-8 -*-
31
"""
4-
Copyright (c) 2016-2022 Philippe Schmouker, schmouk (at) gmail.com
2+
Copyright (c) 2016-2025 Philippe Schmouker, schmouk (at) gmail.com
53
64
Permission is hereby granted, free of charge, to any person obtaining a copy
75
of this software and associated documentation files (the "Software"), to deal
@@ -23,7 +21,8 @@
2321
"""
2422

2523
#=============================================================================
26-
from .baserandom import BaseRandom
24+
from .baserandom import BaseRandom
25+
from .annotation_types import Numerical
2726

2827

2928
#=============================================================================
@@ -32,19 +31,19 @@ class BaseLCG( BaseRandom ):
3231
3332
This module is part of library PyRandLib.
3433
35-
Copyright (c) 2016-2021 Philippe Schmouker
34+
Copyright (c) 2016-2025 Philippe Schmouker
3635
3736
LCG models evaluate pseudo-random numbers suites x(i) as a simple mathem-
3837
atical function of
3938
4039
x(i-1): x(i) = (a*x(i-1) + c) mod m
4140
42-
Results are nevertheless considered to be poor as stated in the
43-
evaluation done by Pierre L'Ecuyer and Richard Simard (Universite de
44-
Montreal) in 'TestU01: A C Library for Empirical Testing of Random Number
45-
Generators - ACM Transactions on Mathematical Software, vol.33 n.4,
46-
pp.22-40, August 2007'. It is not recommended to use such pseudo-random
47-
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.
4847
4948
See FastRand32 for a 2^32 (i.e. 4.3e+9) period LC-Generator with very low
5049
computation time but shorter period and worse randomness characteristics
@@ -54,73 +53,52 @@ class BaseLCG( BaseRandom ):
5453
characteristics than for FastRand32.
5554
5655
Furthermore this class is callable:
57-
rand = BaseLCG()
58-
print( rand() ) # prints a uniform pseudo-random value within [0.0, 1.0)
59-
print( rand(a) ) # prints a uniform pseudo-random value within [0.0, a)
60-
print( rand(a,b) ) # prints a uniform 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)
6160
6261
Reminder:
6362
We give you here below a copy of the table of tests for the LCGs that have
6463
been implemented in PyRandLib, as provided in paper "TestU01, ..." - see
6564
file README.md.
6665
67-
| PyRabndLib class | TU01 generator name | Memory Usage | Period | time-32bits | time-64 bits | SmallCrush fails | Crush fails | BigCrush fails |
68-
| ---------------- | ---------------------------------- | --------------- | ------- | ----------- | ------------ | ---------------- | ----------- | -------------- |
69-
| FastRand32 | LCG(2^32, 69069, 1) | 1 x 4-bytes | 2^32 | 3.20 | 0.67 | 11 | 106 | *too many* |
70-
| 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 |
7170
7271
* _small crush_ is a small set of simple tests that quickly tests some of
73-
the expected characteristics for a pretty good PRG;
72+
the expected characteristics for a pretty good PRNG;
7473
* _crush_ is a bigger set of tests that test more deeply expected random
7574
characteristics;
76-
* _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
7776
should definitively pass.
7877
"""
7978

80-
#------------------------------------------------------------------------=
81-
def __init__(self, _seedState: int = None) -> None:
79+
#-------------------------------------------------------------------------
80+
def __init__(self, _seedState: Numerical = None) -> None:
8281
"""Constructor.
8382
84-
Should inSeed be None or not an integer then the local
85-
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.
8688
"""
87-
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
8891

8992

90-
#------------------------------------------------------------------------=
91-
def random(self) -> float:
92-
"""This is the core of the pseudo-random generator.
93-
94-
Returned values are within [0.0, 1.0).
95-
Inheriting classes HAVE TO IMPLEMENT this method - see FastRand32
96-
for an example. It should use and initialize attribute self._value.
97-
"""
98-
raise NotImplementedError()
99-
100-
101-
#------------------------------------------------------------------------=
93+
#-------------------------------------------------------------------------
10294
def getstate(self) -> int:
10395
"""Returns an object capturing the current internal state of the generator.
10496
10597
This object can be passed to setstate() to restore the state.
106-
For LCG, the state is defined with a single integer, 'self._value',
107-
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
108100
inheriting class.
109101
"""
110-
return self._value
111-
112-
113-
#------------------------------------------------------------------------=
114-
def setstate(self, _state: int) -> None:
115-
"""Restores the internal state of the generator.
116-
117-
_state should have been obtained from a previous call to getstate(),
118-
and setstate() restores the internal state of the generator to what
119-
it was at the time setstate() was called.
120-
Inheriting classes HAVE TO IMPLEMENT this method - see FastRand32
121-
for an example. It should initialize attribute self._value.
122-
"""
123-
raise NotImplementedError()
124-
102+
return self._state
125103

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

0 commit comments

Comments
 (0)