|
| 1 | +""" |
| 2 | +Copyright (c) 2025 Philippe Schmouker, ph (dot) schmouker (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 Any |
| 25 | +import pytest |
| 26 | + |
| 27 | +from PyRandLib.xoroshiro1024 import Xoroshiro1024 |
| 28 | + |
| 29 | + |
| 30 | +#============================================================================= |
| 31 | +class TestXoroshiro1024: |
| 32 | + """Tests class Xoroshiro1024. |
| 33 | + """ |
| 34 | + |
| 35 | + Xoroshiro1024_STATE_SIZE = 16 |
| 36 | + |
| 37 | + #------------------------------------------------------------------------- |
| 38 | + def test_class(self): |
| 39 | + assert Xoroshiro1024._NORMALIZE == 1.0 / (1 << 64) |
| 40 | + assert Xoroshiro1024._OUT_BITS == 64 |
| 41 | + |
| 42 | + #------------------------------------------------------------------------- |
| 43 | + def test_init_empty(self): |
| 44 | + xrsr = Xoroshiro1024() |
| 45 | + assert xrsr._STATE_SIZE == TestXoroshiro1024.Xoroshiro1024_STATE_SIZE |
| 46 | + assert xrsr._index == 0 |
| 47 | + assert xrsr.gauss_next is None # type: ignore |
| 48 | + assert all(isinstance(s, int) for s in xrsr._state) |
| 49 | + assert all(0 <= s < (1 << 64) for s in xrsr._state) # type: ignore |
| 50 | + |
| 51 | + #------------------------------------------------------------------------- |
| 52 | + def test_init_int(self): |
| 53 | + xrsr = Xoroshiro1024(1) |
| 54 | + assert xrsr._index == 0 |
| 55 | + assert xrsr.gauss_next is None # type: ignore |
| 56 | + assert xrsr._state[ 1] == 0xbeeb8da1658eec67 |
| 57 | + assert xrsr._state[ 4] == 0x71bb54d8d101b5b9 |
| 58 | + assert xrsr._state[ 7] == 0x85e7bb0f12278575 |
| 59 | + assert xrsr._state[10] == 0x6775dc7701564f61 |
| 60 | + assert xrsr._state[13] == 0x87b341d690d7a28a |
| 61 | + |
| 62 | + xrsr = Xoroshiro1024(-2) |
| 63 | + assert xrsr._index == 0 |
| 64 | + assert xrsr.gauss_next is None # type: ignore |
| 65 | + assert xrsr._state[ 1] == 0xba56949915dcf9e9 |
| 66 | + assert xrsr._state[ 4] == 0x7842841591543f1d |
| 67 | + assert xrsr._state[ 7] == 0x1e2b53fb7bd63f05 |
| 68 | + assert xrsr._state[10] == 0x2b724bbbfb591868 |
| 69 | + assert xrsr._state[13] == 0x8457d34b5125f667 |
| 70 | + |
| 71 | + xrsr = Xoroshiro1024(0x0123_4567_89ab_cdef) |
| 72 | + assert xrsr._index == 0 |
| 73 | + assert xrsr.gauss_next is None # type: ignore |
| 74 | + assert xrsr._state[ 0] == 0x157a3807a48faa9d |
| 75 | + assert xrsr._state[ 3] == 0xa2d419334c4667ec |
| 76 | + assert xrsr._state[ 6] == 0xb8fc5b1060708c05 |
| 77 | + assert xrsr._state[ 9] == 0x2680d065cb73ece7 |
| 78 | + assert xrsr._state[12] == 0x8eba85b28df77747 |
| 79 | + assert xrsr._state[15] == 0xd7ebcca19d49c3f5 |
| 80 | + |
| 81 | + xrsr = Xoroshiro1024(-8_870_000_000_000_000_000) |
| 82 | + assert xrsr._index == 0 |
| 83 | + assert xrsr.gauss_next is None # type: ignore |
| 84 | + assert xrsr._state[ 1] == 0xe2fbc345a799b5aa |
| 85 | + assert xrsr._state[ 4] == 0x2a03b9aff2bfd421 |
| 86 | + assert xrsr._state[ 7] == 0xe6d2502493ff622e |
| 87 | + assert xrsr._state[10] == 0x4592e2e878ff1b75 |
| 88 | + assert xrsr._state[13] == 0xfbe6cd715ff52a4a |
| 89 | + |
| 90 | + xrsr = Xoroshiro1024(8_870_000_000_000_000_000) |
| 91 | + assert xrsr._index == 0 |
| 92 | + assert xrsr.gauss_next is None # type: ignore |
| 93 | + assert xrsr._state[ 2] == 0x4246cbb1a64bf70c |
| 94 | + assert xrsr._state[ 5] == 0x56d25f68391b2f83 |
| 95 | + assert xrsr._state[ 8] == 0x13d184a1443e3dbe |
| 96 | + assert xrsr._state[11] == 0xff42f03c6e8cba89 |
| 97 | + assert xrsr._state[14] == 0x74d601c8c6c14f90 |
| 98 | + |
| 99 | + xrsr = Xoroshiro1024(0xffff_ffff_ffff_fffe_ffff_ffff_ffff_fffd) |
| 100 | + assert xrsr._index == 0 |
| 101 | + assert xrsr.gauss_next is None # type: ignore |
| 102 | + assert xrsr._state[ 0] == 0xf75f04cbb5a1a1dd |
| 103 | + assert xrsr._state[ 3] == 0x6f9fb04b092bd30a |
| 104 | + assert xrsr._state[ 6] == 0x7a5f67e38e997e3f |
| 105 | + assert xrsr._state[ 9] == 0x56a7458a6eece57b |
| 106 | + assert xrsr._state[12] == 0x149cc0b2e9f5efed |
| 107 | + assert xrsr._state[15] == 0x4a78cd4fccb7e9f8 |
| 108 | + |
| 109 | + #------------------------------------------------------------------------- |
| 110 | + def test_init_float(self): |
| 111 | + xrsr = Xoroshiro1024(0.357) |
| 112 | + assert xrsr._index == 0 |
| 113 | + assert xrsr.gauss_next is None # type: ignore |
| 114 | + assert xrsr._state[ 0] == 0x5fee464f36fc42c3 |
| 115 | + assert xrsr._state[ 3] == 0x77714db9e870d702 |
| 116 | + assert xrsr._state[ 6] == 0x1c4d126a40f3f8a9 |
| 117 | + assert xrsr._state[ 9] == 0xe8f9525bf6c56aef |
| 118 | + assert xrsr._state[12] == 0x102227a35cb75364 |
| 119 | + assert xrsr._state[15] == 0xd619e21c3a243eb0 |
| 120 | + |
| 121 | + xrsr = Xoroshiro1024(1.0) |
| 122 | + assert xrsr._index == 0 |
| 123 | + assert xrsr.gauss_next is None # type: ignore |
| 124 | + assert all(isinstance(s, int) for s in xrsr._state) |
| 125 | + assert all(0 <= s < (1 << 64) for s in xrsr._state) # type: ignore |
| 126 | + |
| 127 | + with pytest.raises(ValueError): |
| 128 | + xrsr = Xoroshiro1024(-0.0001) |
| 129 | + with pytest.raises(ValueError): |
| 130 | + xrsr = Xoroshiro1024(1.001) |
| 131 | + |
| 132 | + #------------------------------------------------------------------------- |
| 133 | + def test_init_state(self): |
| 134 | + xrsr = Xoroshiro1024(tuple(i for i in range(TestXoroshiro1024.Xoroshiro1024_STATE_SIZE))) # type: ignore |
| 135 | + assert xrsr._index == 0 |
| 136 | + assert xrsr.gauss_next is None # type: ignore |
| 137 | + assert xrsr._state == [i for i in range(TestXoroshiro1024.Xoroshiro1024_STATE_SIZE)] # type: ignore |
| 138 | + |
| 139 | + with pytest.raises(TypeError): |
| 140 | + # due to unhashable lists bug in Python 3.10 |
| 141 | + xrsr = Xoroshiro1024(list(i+10 for i in range(TestXoroshiro1024.Xoroshiro1024_STATE_SIZE))) # type: ignore |
| 142 | + assert xrsr._index == 0 |
| 143 | + assert xrsr.gauss_next is None # type: ignore |
| 144 | + assert xrsr._state == list(i+10 for i in range(TestXoroshiro1024.Xoroshiro1024_STATE_SIZE)) # type: ignore |
| 145 | + |
| 146 | + with pytest.raises(TypeError): |
| 147 | + xrsr = Xoroshiro1024((1, 2, 3)) # type: ignore |
| 148 | + with pytest.raises(TypeError): |
| 149 | + xrsr = Xoroshiro1024((i for i in range(18))) # type: ignore |
| 150 | + with pytest.raises(TypeError): |
| 151 | + xrsr = Xoroshiro1024([1, 2, 3]) # type: ignore |
| 152 | + with pytest.raises(TypeError): |
| 153 | + xrsr = Xoroshiro1024([i for i in range(18)]) # type: ignore |
| 154 | + with pytest.raises(TypeError): |
| 155 | + xrsr = Xoroshiro1024(set()) # type: ignore |
| 156 | + |
| 157 | + #------------------------------------------------------------------------- |
| 158 | + def test_next(self): |
| 159 | + xrsr = Xoroshiro1024(0x0123_4567_89ab_cdef) |
| 160 | + assert xrsr.gauss_next is None # type: ignore |
| 161 | + assert xrsr._index == 0 |
| 162 | + assert xrsr._state[ 0] == 0x157a3807a48faa9d |
| 163 | + assert xrsr._state[ 3] == 0xa2d419334c4667ec |
| 164 | + assert xrsr._state[ 6] == 0xb8fc5b1060708c05 |
| 165 | + assert xrsr._state[ 9] == 0x2680d065cb73ece7 |
| 166 | + assert xrsr._state[12] == 0x8eba85b28df77747 |
| 167 | + assert xrsr._state[15] == 0xd7ebcca19d49c3f5 |
| 168 | + |
| 169 | + for v in [0xa2c2a42038d4ec3d, 0x3819987c267eb726, 0xa437023430223ecf, 0x26c27c4ef6c0b41b, 0x8dac31b4ce3806cb]: |
| 170 | + assert xrsr.next() == v |
| 171 | + |
| 172 | + assert xrsr.gauss_next is None # type: ignore |
| 173 | + assert xrsr._index == 5 |
| 174 | + assert xrsr.gauss_next is None # type: ignore |
| 175 | + assert xrsr._state[ 1] == 0x648a17705da44419 |
| 176 | + assert xrsr._state[ 4] == 0x1fd7e2f11d1d3f70 |
| 177 | + assert xrsr._state[ 7] == 0x8931545f4f9ea651 |
| 178 | + assert xrsr._state[10] == 0xcdb8c9cd9a62da0f |
| 179 | + assert xrsr._state[13] == 0x97f6c69811cfb13b |
| 180 | + |
| 181 | + #------------------------------------------------------------------------- |
| 182 | + def test_seed(self): |
| 183 | + xrsr = Xoroshiro1024() |
| 184 | + |
| 185 | + xrsr.seed(0xffff_ffff_ffff_fffe_ffff_ffff_ffff_fffd) |
| 186 | + assert xrsr._index == 0 |
| 187 | + assert xrsr.gauss_next is None # type: ignore |
| 188 | + assert xrsr._state[ 0] == 0xf75f04cbb5a1a1dd |
| 189 | + assert xrsr._state[ 3] == 0x6f9fb04b092bd30a |
| 190 | + assert xrsr._state[ 6] == 0x7a5f67e38e997e3f |
| 191 | + assert xrsr._state[ 9] == 0x56a7458a6eece57b |
| 192 | + assert xrsr._state[12] == 0x149cc0b2e9f5efed |
| 193 | + assert xrsr._state[15] == 0x4a78cd4fccb7e9f8 |
| 194 | + |
| 195 | + xrsr.seed(0.357) |
| 196 | + assert xrsr._index == 0 |
| 197 | + assert xrsr.gauss_next is None # type: ignore |
| 198 | + assert xrsr._state[ 0] == 0x5fee464f36fc42c3 |
| 199 | + assert xrsr._state[ 3] == 0x77714db9e870d702 |
| 200 | + assert xrsr._state[ 6] == 0x1c4d126a40f3f8a9 |
| 201 | + assert xrsr._state[ 9] == 0xe8f9525bf6c56aef |
| 202 | + assert xrsr._state[12] == 0x102227a35cb75364 |
| 203 | + assert xrsr._state[15] == 0xd619e21c3a243eb0 |
| 204 | + |
| 205 | + with pytest.raises(ValueError): |
| 206 | + xrsr.seed(-0.0001) |
| 207 | + with pytest.raises(ValueError): |
| 208 | + xrsr.seed(1.001) |
| 209 | + |
| 210 | + xrsr.seed() |
| 211 | + assert xrsr._index == 0 |
| 212 | + assert xrsr.gauss_next is None # type: ignore |
| 213 | + assert all(isinstance(s, int) for s in xrsr._state) |
| 214 | + assert all(0 < s < (1 << 64) for s in xrsr._state) # type: ignore |
| 215 | + |
| 216 | + with pytest.raises(TypeError): |
| 217 | + xrsr.seed((1, 2, 3)) # type: ignore |
| 218 | + with pytest.raises(TypeError): |
| 219 | + xrsr.seed((1, 2, 3, 4, 5)) # type: ignore |
| 220 | + with pytest.raises(TypeError): |
| 221 | + xrsr.seed([1, 2, 3]) # type: ignore |
| 222 | + with pytest.raises(TypeError): |
| 223 | + xrsr.seed([1, 2, 3, 4, 5]) # type: ignore |
| 224 | + with pytest.raises(TypeError): |
| 225 | + xrsr.seed(set()) # type: ignore |
| 226 | + |
| 227 | + #------------------------------------------------------------------------- |
| 228 | + def test_setstate(self): |
| 229 | + xrsr = Xoroshiro1024() |
| 230 | + |
| 231 | + xrsr.setstate() |
| 232 | + assert xrsr._index == 0 |
| 233 | + assert xrsr.gauss_next is None # type: ignore |
| 234 | + assert all(isinstance(s, int) for s in xrsr._state) |
| 235 | + assert all(0 < s < (1 << 64) for s in xrsr._state) # type: ignore |
| 236 | + |
| 237 | + with pytest.raises(TypeError): |
| 238 | + xrsr.setstate(1) # type: ignore |
| 239 | + |
| 240 | + with pytest.raises(TypeError): |
| 241 | + xrsr.setstate(0.1) # type: ignore |
| 242 | + |
| 243 | + with pytest.raises(TypeError): |
| 244 | + xrsr.setstate("123") # type: ignore |
| 245 | + |
| 246 | + xrsr.setstate((tuple(i+31 for i in range(TestXoroshiro1024.Xoroshiro1024_STATE_SIZE)), 3)) # type: ignore |
| 247 | + assert xrsr.gauss_next is None # type: ignore |
| 248 | + assert xrsr._index == 3 |
| 249 | + assert xrsr.gauss_next is None # type: ignore |
| 250 | + assert xrsr._state == [i+31 for i in range(TestXoroshiro1024.Xoroshiro1024_STATE_SIZE)] # type: ignore |
| 251 | + |
| 252 | + xrsr.setstate([[i+41 for i in range(TestXoroshiro1024.Xoroshiro1024_STATE_SIZE)], TestXoroshiro1024.Xoroshiro1024_STATE_SIZE + 8]) # type: ignore |
| 253 | + assert xrsr.gauss_next is None # type: ignore |
| 254 | + assert xrsr._index == (TestXoroshiro1024.Xoroshiro1024_STATE_SIZE + 8) % TestXoroshiro1024.Xoroshiro1024_STATE_SIZE |
| 255 | + assert xrsr.gauss_next is None # type: ignore |
| 256 | + assert xrsr._state == [i+41 for i in range(TestXoroshiro1024.Xoroshiro1024_STATE_SIZE)] # type: ignore |
| 257 | + |
| 258 | + xrsr.setstate([tuple(i+51 for i in range(TestXoroshiro1024.Xoroshiro1024_STATE_SIZE)), 3]) # type: ignore |
| 259 | + assert xrsr.gauss_next is None # type: ignore |
| 260 | + assert xrsr._index == 3 % TestXoroshiro1024.Xoroshiro1024_STATE_SIZE |
| 261 | + assert xrsr.gauss_next is None # type: ignore |
| 262 | + assert xrsr._state == [i+51 for i in range(TestXoroshiro1024.Xoroshiro1024_STATE_SIZE)] # type: ignore |
| 263 | + |
| 264 | + xrsr.setstate(([i+61 for i in range(TestXoroshiro1024.Xoroshiro1024_STATE_SIZE)], TestXoroshiro1024.Xoroshiro1024_STATE_SIZE + 8)) # type: ignore |
| 265 | + assert xrsr.gauss_next is None # type: ignore |
| 266 | + assert xrsr._index == (TestXoroshiro1024.Xoroshiro1024_STATE_SIZE + 8) % TestXoroshiro1024.Xoroshiro1024_STATE_SIZE |
| 267 | + assert xrsr.gauss_next is None # type: ignore |
| 268 | + assert xrsr._state == [i+61 for i in range(TestXoroshiro1024.Xoroshiro1024_STATE_SIZE)] # type: ignore |
| 269 | + |
| 270 | + xrsr.setstate(tuple(i+11 for i in range(TestXoroshiro1024.Xoroshiro1024_STATE_SIZE))) # type: ignore |
| 271 | + assert xrsr.gauss_next is None # type: ignore |
| 272 | + assert xrsr._index == 0 |
| 273 | + assert xrsr.gauss_next is None # type: ignore |
| 274 | + assert xrsr._state == [i+11 for i in range(TestXoroshiro1024.Xoroshiro1024_STATE_SIZE)] # type: ignore |
| 275 | + |
| 276 | + xrsr.setstate([i+21 for i in range(TestXoroshiro1024.Xoroshiro1024_STATE_SIZE)]) # type: ignore |
| 277 | + assert xrsr.gauss_next is None # type: ignore |
| 278 | + assert xrsr._index == 0 |
| 279 | + assert xrsr.gauss_next is None # type: ignore |
| 280 | + assert xrsr._state == [i+21 for i in range(TestXoroshiro1024.Xoroshiro1024_STATE_SIZE)] # type: ignore |
| 281 | + |
| 282 | + with pytest.raises(TypeError): |
| 283 | + xrsr.setstate([1, 2]) |
| 284 | + with pytest.raises(TypeError): |
| 285 | + xrsr.setstate((1, 2, 3, 4, 5)) # type: ignore |
| 286 | + with pytest.raises(TypeError): |
| 287 | + xrsr.setstate([1, 2, '3', 4]) # type: ignore |
| 288 | + with pytest.raises(TypeError): |
| 289 | + xrsr.setstate([11, 12, 13.1, 14]) # type: ignore |
| 290 | + _state: list[Any] |
| 291 | + with pytest.raises(ValueError): |
| 292 | + _state = [i+1 for i in range(TestXoroshiro1024.Xoroshiro1024_STATE_SIZE)] # type: ignore |
| 293 | + _state[TestXoroshiro1024.Xoroshiro1024_STATE_SIZE - 2] = -1 |
| 294 | + xrsr.setstate(_state) # type: ignore |
| 295 | + with pytest.raises(ValueError): |
| 296 | + _state = [i+1 for i in range(TestXoroshiro1024.Xoroshiro1024_STATE_SIZE)] # type: ignore |
| 297 | + _state[TestXoroshiro1024.Xoroshiro1024_STATE_SIZE - 3] = 0.321 |
| 298 | + xrsr.setstate(_state) # type: ignore |
| 299 | + with pytest.raises(ValueError): |
| 300 | + _state = [i+1 for i in range(TestXoroshiro1024.Xoroshiro1024_STATE_SIZE)] # type: ignore |
| 301 | + _state[TestXoroshiro1024.Xoroshiro1024_STATE_SIZE - 5] = {1, 2} |
| 302 | + xrsr.setstate(_state) # type: ignore |
0 commit comments