|
| 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.xoroshiro512 import Xoroshiro512 |
| 28 | + |
| 29 | + |
| 30 | +#============================================================================= |
| 31 | +class TestXoroshiro512: |
| 32 | + """Tests class Xoroshiro512. |
| 33 | + """ |
| 34 | + |
| 35 | + Xoroshiro512_STATE_SIZE = 8 |
| 36 | + |
| 37 | + #------------------------------------------------------------------------- |
| 38 | + def test_class(self): |
| 39 | + assert Xoroshiro512._NORMALIZE == 1.0 / (1 << 64) |
| 40 | + assert Xoroshiro512._OUT_BITS == 64 |
| 41 | + |
| 42 | + #------------------------------------------------------------------------- |
| 43 | + def test_init_empty(self): |
| 44 | + xrsr = Xoroshiro512() |
| 45 | + assert xrsr._STATE_SIZE == TestXoroshiro512.Xoroshiro512_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 = Xoroshiro512(1) |
| 54 | + assert xrsr._index == 0 |
| 55 | + assert xrsr.gauss_next is None # type: ignore |
| 56 | + assert xrsr._state[0] == 0x910a2dec89025cc1 |
| 57 | + assert xrsr._state[1] == 0xbeeb8da1658eec67 |
| 58 | + assert xrsr._state[2] == 0xf893a2eefb32555e |
| 59 | + assert xrsr._state[3] == 0x71c18690ee42c90b |
| 60 | + assert xrsr._state[4] == 0x71bb54d8d101b5b9 |
| 61 | + assert xrsr._state[5] == 0xc34d0bff90150280 |
| 62 | + assert xrsr._state[6] == 0xe099ec6cd7363ca5 |
| 63 | + assert xrsr._state[7] == 0x85e7bb0f12278575 |
| 64 | + |
| 65 | + xrsr = Xoroshiro512(-2) |
| 66 | + assert xrsr._index == 0 |
| 67 | + assert xrsr.gauss_next is None # type: ignore |
| 68 | + assert xrsr._state[0] == 0xf3203e9039f4a821 |
| 69 | + assert xrsr._state[1] == 0xba56949915dcf9e9 |
| 70 | + assert xrsr._state[2] == 0xd0d5127a96e8d90d |
| 71 | + assert xrsr._state[3] == 0x1ef156bb76650c37 |
| 72 | + assert xrsr._state[4] == 0x7842841591543f1d |
| 73 | + assert xrsr._state[5] == 0xd85ab7a2b154095a |
| 74 | + assert xrsr._state[6] == 0xea909a92e113bf3c |
| 75 | + assert xrsr._state[7] == 0x1e2b53fb7bd63f05 |
| 76 | + |
| 77 | + xrsr = Xoroshiro512(0x0123_4567_89ab_cdef) |
| 78 | + assert xrsr._index == 0 |
| 79 | + assert xrsr.gauss_next is None # type: ignore |
| 80 | + assert xrsr._state[0] == 0x157a3807a48faa9d |
| 81 | + assert xrsr._state[1] == 0xd573529b34a1d093 |
| 82 | + assert xrsr._state[2] == 0x2f90b72e996dccbe |
| 83 | + assert xrsr._state[3] == 0xa2d419334c4667ec |
| 84 | + assert xrsr._state[4] == 0x01404ce914938008 |
| 85 | + assert xrsr._state[5] == 0x14bc574c2a2b4c72 |
| 86 | + assert xrsr._state[6] == 0xb8fc5b1060708c05 |
| 87 | + assert xrsr._state[7] == 0x8931545f4f9ea651 |
| 88 | + |
| 89 | + xrsr = Xoroshiro512(-8_870_000_000_000_000_000) |
| 90 | + assert xrsr._index == 0 |
| 91 | + assert xrsr.gauss_next is None # type: ignore |
| 92 | + assert xrsr._state[0] == 0x48bbc5b84275f3ca |
| 93 | + assert xrsr._state[1] == 0xe2fbc345a799b5aa |
| 94 | + assert xrsr._state[2] == 0x86ce19a135fba0de |
| 95 | + assert xrsr._state[3] == 0x637c87187035ea06 |
| 96 | + assert xrsr._state[4] == 0x2a03b9aff2bfd421 |
| 97 | + assert xrsr._state[5] == 0x534fe17cac5d7a22 |
| 98 | + assert xrsr._state[6] == 0x95d0c8e531644d42 |
| 99 | + assert xrsr._state[7] == 0xe6d2502493ff622e |
| 100 | + |
| 101 | + xrsr = Xoroshiro512(8_870_000_000_000_000_000) |
| 102 | + assert xrsr._index == 0 |
| 103 | + assert xrsr.gauss_next is None # type: ignore |
| 104 | + assert xrsr._state[0] == 0xeede014d9a5a6108 |
| 105 | + assert xrsr._state[1] == 0xa6eb6466bac9f251 |
| 106 | + assert xrsr._state[2] == 0x4246cbb1a64bf70c |
| 107 | + assert xrsr._state[3] == 0xaf6aa8f43ebb8659 |
| 108 | + assert xrsr._state[4] == 0xe1b0fb2c7e764cdb |
| 109 | + assert xrsr._state[5] == 0x56d25f68391b2f83 |
| 110 | + assert xrsr._state[6] == 0x1408795faf81b73d |
| 111 | + assert xrsr._state[7] == 0xe0c07d9420f2f41e |
| 112 | + |
| 113 | + xrsr = Xoroshiro512(0xffff_ffff_ffff_fffe_ffff_ffff_ffff_fffd) |
| 114 | + assert xrsr._index == 0 |
| 115 | + assert xrsr.gauss_next is None # type: ignore |
| 116 | + assert xrsr._state[0] == 0xf75f04cbb5a1a1dd |
| 117 | + assert xrsr._state[1] == 0xec779c3693f88501 |
| 118 | + assert xrsr._state[2] == 0xfed9eeb4936de39d |
| 119 | + assert xrsr._state[3] == 0x6f9fb04b092bd30a |
| 120 | + assert xrsr._state[4] == 0x260ffb0260bbbe5f |
| 121 | + assert xrsr._state[5] == 0x082cfe8866fac366 |
| 122 | + assert xrsr._state[6] == 0x7a5f67e38e997e3f |
| 123 | + assert xrsr._state[7] == 0xd7c07017388fa2af |
| 124 | + |
| 125 | + #------------------------------------------------------------------------- |
| 126 | + def test_init_float(self): |
| 127 | + xrsr = Xoroshiro512(0.357) |
| 128 | + assert xrsr._index == 0 |
| 129 | + assert xrsr.gauss_next is None # type: ignore |
| 130 | + assert xrsr._state[0] == 0x5fee464f36fc42c3 |
| 131 | + assert xrsr._state[1] == 0x954faf5a9ad49cf8 |
| 132 | + assert xrsr._state[2] == 0xa985465a4a5fc644 |
| 133 | + assert xrsr._state[3] == 0x77714db9e870d702 |
| 134 | + assert xrsr._state[4] == 0xa3aac457d81d552c |
| 135 | + assert xrsr._state[5] == 0xbcf1fb888caf4f02 |
| 136 | + assert xrsr._state[6] == 0x1c4d126a40f3f8a9 |
| 137 | + assert xrsr._state[7] == 0xe6b536617ee8b60c |
| 138 | + |
| 139 | + xrsr = Xoroshiro512(1.0) |
| 140 | + assert xrsr._index == 0 |
| 141 | + assert xrsr.gauss_next is None # type: ignore |
| 142 | + assert all(isinstance(s, int) for s in xrsr._state) |
| 143 | + assert all(0 <= s < (1 << 64) for s in xrsr._state) # type: ignore |
| 144 | + |
| 145 | + with pytest.raises(ValueError): |
| 146 | + xrsr = Xoroshiro512(-0.0001) |
| 147 | + with pytest.raises(ValueError): |
| 148 | + xrsr = Xoroshiro512(1.001) |
| 149 | + |
| 150 | + #------------------------------------------------------------------------- |
| 151 | + def test_init_state(self): |
| 152 | + xrsr = Xoroshiro512(tuple(i for i in range(TestXoroshiro512.Xoroshiro512_STATE_SIZE))) # type: ignore |
| 153 | + assert xrsr._index == 0 |
| 154 | + assert xrsr.gauss_next is None # type: ignore |
| 155 | + assert xrsr._state == [i for i in range(TestXoroshiro512.Xoroshiro512_STATE_SIZE)] # type: ignore |
| 156 | + |
| 157 | + with pytest.raises(TypeError): |
| 158 | + # due to unhashable lists bug in Python 3.10 |
| 159 | + xrsr = Xoroshiro512(list(i+10 for i in range(TestXoroshiro512.Xoroshiro512_STATE_SIZE))) # type: ignore |
| 160 | + assert xrsr._index == 0 |
| 161 | + assert xrsr.gauss_next is None # type: ignore |
| 162 | + assert xrsr._state == list(i+10 for i in range(TestXoroshiro512.Xoroshiro512_STATE_SIZE)) # type: ignore |
| 163 | + |
| 164 | + with pytest.raises(TypeError): |
| 165 | + xrsr = Xoroshiro512((1, 2, 3)) # type: ignore |
| 166 | + with pytest.raises(TypeError): |
| 167 | + xrsr = Xoroshiro512((i for i in range(18))) # type: ignore |
| 168 | + with pytest.raises(TypeError): |
| 169 | + xrsr = Xoroshiro512([1, 2, 3]) # type: ignore |
| 170 | + with pytest.raises(TypeError): |
| 171 | + xrsr = Xoroshiro512([i for i in range(18)]) # type: ignore |
| 172 | + with pytest.raises(TypeError): |
| 173 | + xrsr = Xoroshiro512(set()) # type: ignore |
| 174 | + |
| 175 | + #------------------------------------------------------------------------- |
| 176 | + def test_next(self): |
| 177 | + xrsr = Xoroshiro512(0x0123_4567_89ab_cdef) |
| 178 | + assert xrsr.gauss_next is None # type: ignore |
| 179 | + assert xrsr._index == 0 |
| 180 | + assert xrsr._state[0] == 0x157a3807a48faa9d |
| 181 | + assert xrsr._state[1] == 0xd573529b34a1d093 |
| 182 | + assert xrsr._state[2] == 0x2f90b72e996dccbe |
| 183 | + assert xrsr._state[3] == 0xa2d419334c4667ec |
| 184 | + assert xrsr._state[4] == 0x01404ce914938008 |
| 185 | + assert xrsr._state[5] == 0x14bc574c2a2b4c72 |
| 186 | + assert xrsr._state[6] == 0xb8fc5b1060708c05 |
| 187 | + assert xrsr._state[7] == 0x8931545f4f9ea651 |
| 188 | + |
| 189 | + for v in [0xa2c2a42038d4ec3d, 0x5fc25d0738e7b0f, 0x8cdae320589ff91e, 0x5ef9741cae1d2a1c, 0xb5bfb1afdbeb04dd]: |
| 190 | + assert xrsr.next() == v |
| 191 | + |
| 192 | + assert xrsr.gauss_next is None # type: ignore |
| 193 | + assert xrsr._index == 0 |
| 194 | + assert xrsr.gauss_next is None # type: ignore |
| 195 | + assert xrsr._state[0] == 0x2dd1d8834a1d1abe |
| 196 | + assert xrsr._state[1] == 0xfd4348c7c59ed738 |
| 197 | + assert xrsr._state[2] == 0xe8c9a4d483fa1ce6 |
| 198 | + assert xrsr._state[3] == 0x90f3152a081b547f |
| 199 | + assert xrsr._state[4] == 0xadf094a1bc23213c |
| 200 | + assert xrsr._state[5] == 0x08bb748601635214 |
| 201 | + assert xrsr._state[6] == 0xfad74f72516c3bfd |
| 202 | + assert xrsr._state[7] == 0x8f2b04287d66d6e6 |
| 203 | + |
| 204 | + #------------------------------------------------------------------------- |
| 205 | + def test_seed(self): |
| 206 | + xrsr = Xoroshiro512() |
| 207 | + |
| 208 | + xrsr.seed(0xffff_ffff_ffff_fffe_ffff_ffff_ffff_fffd) |
| 209 | + assert xrsr._index == 0 |
| 210 | + assert xrsr.gauss_next is None # type: ignore |
| 211 | + assert xrsr._state[0] == 0xf75f04cbb5a1a1dd |
| 212 | + assert xrsr._state[1] == 0xec779c3693f88501 |
| 213 | + assert xrsr._state[2] == 0xfed9eeb4936de39d |
| 214 | + assert xrsr._state[3] == 0x6f9fb04b092bd30a |
| 215 | + assert xrsr._state[4] == 0x260ffb0260bbbe5f |
| 216 | + assert xrsr._state[5] == 0x082cfe8866fac366 |
| 217 | + assert xrsr._state[6] == 0x7a5f67e38e997e3f |
| 218 | + assert xrsr._state[7] == 0xd7c07017388fa2af |
| 219 | + |
| 220 | + xrsr.seed(0.357) |
| 221 | + assert xrsr._index == 0 |
| 222 | + assert xrsr.gauss_next is None # type: ignore |
| 223 | + assert xrsr._state[0] == 0x5fee464f36fc42c3 |
| 224 | + assert xrsr._state[1] == 0x954faf5a9ad49cf8 |
| 225 | + assert xrsr._state[2] == 0xa985465a4a5fc644 |
| 226 | + assert xrsr._state[3] == 0x77714db9e870d702 |
| 227 | + assert xrsr._state[4] == 0xa3aac457d81d552c |
| 228 | + assert xrsr._state[5] == 0xbcf1fb888caf4f02 |
| 229 | + assert xrsr._state[6] == 0x1c4d126a40f3f8a9 |
| 230 | + assert xrsr._state[7] == 0xe6b536617ee8b60c |
| 231 | + |
| 232 | + with pytest.raises(ValueError): |
| 233 | + xrsr.seed(-0.0001) |
| 234 | + with pytest.raises(ValueError): |
| 235 | + xrsr.seed(1.001) |
| 236 | + |
| 237 | + xrsr.seed() |
| 238 | + assert xrsr._index == 0 |
| 239 | + assert xrsr.gauss_next is None # type: ignore |
| 240 | + assert all(isinstance(s, int) for s in xrsr._state) |
| 241 | + assert all(0 < s < (1 << 64) for s in xrsr._state) # type: ignore |
| 242 | + |
| 243 | + with pytest.raises(TypeError): |
| 244 | + xrsr.seed((1, 2, 3)) # type: ignore |
| 245 | + with pytest.raises(TypeError): |
| 246 | + xrsr.seed((1, 2, 3, 4, 5)) # type: ignore |
| 247 | + with pytest.raises(TypeError): |
| 248 | + xrsr.seed([1, 2, 3]) # type: ignore |
| 249 | + with pytest.raises(TypeError): |
| 250 | + xrsr.seed([1, 2, 3, 4, 5]) # type: ignore |
| 251 | + with pytest.raises(TypeError): |
| 252 | + xrsr.seed(set()) # type: ignore |
| 253 | + |
| 254 | + #------------------------------------------------------------------------- |
| 255 | + def test_setstate(self): |
| 256 | + xrsr = Xoroshiro512() |
| 257 | + |
| 258 | + xrsr.setstate() |
| 259 | + assert xrsr._index == 0 |
| 260 | + assert xrsr.gauss_next is None # type: ignore |
| 261 | + assert all(isinstance(s, int) for s in xrsr._state) |
| 262 | + assert all(0 < s < (1 << 64) for s in xrsr._state) # type: ignore |
| 263 | + |
| 264 | + with pytest.raises(TypeError): |
| 265 | + xrsr.setstate(1) # type: ignore |
| 266 | + |
| 267 | + with pytest.raises(TypeError): |
| 268 | + xrsr.setstate(0.1) # type: ignore |
| 269 | + |
| 270 | + with pytest.raises(TypeError): |
| 271 | + xrsr.setstate("123") # type: ignore |
| 272 | + |
| 273 | + xrsr.setstate((tuple(i+31 for i in range(TestXoroshiro512.Xoroshiro512_STATE_SIZE)), 3)) # type: ignore |
| 274 | + assert xrsr.gauss_next is None # type: ignore |
| 275 | + assert xrsr._index == 3 |
| 276 | + assert xrsr.gauss_next is None # type: ignore |
| 277 | + assert xrsr._state == [i+31 for i in range(TestXoroshiro512.Xoroshiro512_STATE_SIZE)] # type: ignore |
| 278 | + |
| 279 | + xrsr.setstate([[i+41 for i in range(TestXoroshiro512.Xoroshiro512_STATE_SIZE)], TestXoroshiro512.Xoroshiro512_STATE_SIZE + 8]) # type: ignore |
| 280 | + assert xrsr.gauss_next is None # type: ignore |
| 281 | + assert xrsr._index == 0 |
| 282 | + assert xrsr.gauss_next is None # type: ignore |
| 283 | + assert xrsr._state == [i+41 for i in range(TestXoroshiro512.Xoroshiro512_STATE_SIZE)] # type: ignore |
| 284 | + |
| 285 | + xrsr.setstate([tuple(i+51 for i in range(TestXoroshiro512.Xoroshiro512_STATE_SIZE)), 3]) # type: ignore |
| 286 | + assert xrsr.gauss_next is None # type: ignore |
| 287 | + assert xrsr._index == 3 % TestXoroshiro512.Xoroshiro512_STATE_SIZE |
| 288 | + assert xrsr.gauss_next is None # type: ignore |
| 289 | + assert xrsr._state == [i+51 for i in range(TestXoroshiro512.Xoroshiro512_STATE_SIZE)] # type: ignore |
| 290 | + |
| 291 | + xrsr.setstate(([i+61 for i in range(TestXoroshiro512.Xoroshiro512_STATE_SIZE)], TestXoroshiro512.Xoroshiro512_STATE_SIZE + 8)) # type: ignore |
| 292 | + assert xrsr.gauss_next is None # type: ignore |
| 293 | + assert xrsr._index == 8 % TestXoroshiro512.Xoroshiro512_STATE_SIZE |
| 294 | + assert xrsr.gauss_next is None # type: ignore |
| 295 | + assert xrsr._state == [i+61 for i in range(TestXoroshiro512.Xoroshiro512_STATE_SIZE)] # type: ignore |
| 296 | + |
| 297 | + xrsr.setstate(tuple(i+11 for i in range(TestXoroshiro512.Xoroshiro512_STATE_SIZE))) # type: ignore |
| 298 | + assert xrsr.gauss_next is None # type: ignore |
| 299 | + assert xrsr._index == 0 |
| 300 | + assert xrsr.gauss_next is None # type: ignore |
| 301 | + assert xrsr._state == [i+11 for i in range(TestXoroshiro512.Xoroshiro512_STATE_SIZE)] # type: ignore |
| 302 | + |
| 303 | + xrsr.setstate([i+21 for i in range(TestXoroshiro512.Xoroshiro512_STATE_SIZE)]) # type: ignore |
| 304 | + assert xrsr.gauss_next is None # type: ignore |
| 305 | + assert xrsr._index == 0 |
| 306 | + assert xrsr.gauss_next is None # type: ignore |
| 307 | + assert xrsr._state == [i+21 for i in range(TestXoroshiro512.Xoroshiro512_STATE_SIZE)] # type: ignore |
| 308 | + |
| 309 | + with pytest.raises(TypeError): |
| 310 | + xrsr.setstate([1, 2]) |
| 311 | + with pytest.raises(TypeError): |
| 312 | + xrsr.setstate((1, 2, 3, 4, 5)) # type: ignore |
| 313 | + with pytest.raises(TypeError): |
| 314 | + xrsr.setstate([1, 2, '3', 4]) # type: ignore |
| 315 | + with pytest.raises(TypeError): |
| 316 | + xrsr.setstate([11, 12, 13.1, 14]) # type: ignore |
| 317 | + _state: list[Any] |
| 318 | + with pytest.raises(ValueError): |
| 319 | + _state = [i+1 for i in range(TestXoroshiro512.Xoroshiro512_STATE_SIZE)] # type: ignore |
| 320 | + _state[TestXoroshiro512.Xoroshiro512_STATE_SIZE - 2] = -1 |
| 321 | + xrsr.setstate(_state) # type: ignore |
| 322 | + with pytest.raises(ValueError): |
| 323 | + _state = [i+1 for i in range(TestXoroshiro512.Xoroshiro512_STATE_SIZE)] # type: ignore |
| 324 | + _state[TestXoroshiro512.Xoroshiro512_STATE_SIZE - 3] = 0.321 |
| 325 | + xrsr.setstate(_state) # type: ignore |
| 326 | + with pytest.raises(ValueError): |
| 327 | + _state = [i+1 for i in range(TestXoroshiro512.Xoroshiro512_STATE_SIZE)] # type: ignore |
| 328 | + _state[TestXoroshiro512.Xoroshiro512_STATE_SIZE - 5] = {1, 2} |
| 329 | + xrsr.setstate(_state) # type: ignore |
0 commit comments